Referência fraca - Weak reference

Em programação de computador , uma referência fraca é uma referência que não protege o objeto referenciado da coleta por um coletor de lixo , ao contrário de uma referência forte. Um objecto referenciado única por referências fracas - significando "cada cadeia de referências que atinge o objecto inclui pelo menos uma referência fraca como uma ligação" - é considerado fracamente alcançável , e pode ser tratada como inacessível e por isso podem ser recolhidas em qualquer altura. Algumas linguagens de coleta de lixo apresentam ou suportam vários níveis de referências fracas, como C # , Java , Lisp , OCaml , Perl , Python e PHP desde a versão 7.4.

Usos

As referências fracas têm vários casos de uso comuns. Ao usar a coleta de lixo de contagem de referência , as referências fracas podem quebrar os ciclos de referência , usando uma referência fraca para um link no ciclo. Quando se tem um array associativo (mapeamento, mapa hash) cujas chaves são (referências a) objetos, por exemplo, para conter dados auxiliares sobre objetos, usar referências fracas para as chaves evita manter os objetos vivos apenas por causa de seu uso como uma chave. Quando se tem um objeto onde outros objetos são registrados, como no padrão do observador (particularmente no tratamento de eventos ), se uma referência forte for mantida, os objetos devem ser explicitamente cancelados, caso contrário, ocorre um vazamento de memória (o problema do listener lapsed ), enquanto uma referência fraca remove a necessidade de cancelar o registro. Ao armazenar dados em cache que podem ser recriados se necessário, as referências fracas permitem que o cache seja recuperado, produzindo efetivamente memória descartável. Este último caso (um cache) é distinto dos outros, pois é preferível que os objetos sejam coletados somente se necessário, e há, portanto, uma necessidade de distinções mais finas dentro de referências fracas, aqui uma forma mais forte de uma referência fraca. Em muitos casos, as referências fracas não precisam ser usadas diretamente, em vez de simplesmente usar uma matriz fraca ou outro contêiner cujas chaves ou valores são referências fracas.

Coleta de lixo

A coleta de lixo é usada para limpar objetos não usados ​​e, assim, reduzir o potencial de vazamentos de memória e corrupção de dados. Existem dois tipos principais de coleta de lixo: rastreamento e contagem de referência . Os esquemas de contagem de referência registram o número de referências a um determinado objeto e coletam o objeto quando a contagem de referência torna-se zero. A contagem de referências não pode coletar referências cíclicas (ou circulares) porque apenas um objeto pode ser coletado por vez. Grupos de objetos de referência mútua que não são diretamente referenciados por outros objetos e são inacessíveis podem, portanto, tornar-se residentes permanentemente; se um aplicativo gerar continuamente esses grupos inacessíveis de objetos inacessíveis, isso terá o efeito de um vazamento de memória . Referências fracas (referências que não são contadas na contagem de referência) podem ser usadas para resolver o problema de referências circulares se os ciclos de referência forem evitados usando referências fracas para algumas das referências dentro do grupo.

Um caso muito comum de tais distinções de referência forte vs. fraca é em estruturas de árvore, como o Document Object Model (DOM), onde as referências pai para filho são fortes, mas referências filho para pai são fracas. Por exemplo, a estrutura Cocoa da Apple recomenda essa abordagem. Na verdade, mesmo quando o gráfico do objeto não é uma árvore, uma estrutura de árvore pode muitas vezes ser imposta pela noção de propriedade do objeto, onde as relações de propriedade são fortes e formam uma árvore, e as relações de não propriedade são fracas e não são necessárias para formar a árvore - esta abordagem é comum em C ++ (pré-C ++ 11), usando ponteiros brutos como referências fracas. Essa abordagem, no entanto, tem a desvantagem de não permitir a capacidade de detectar quando um branch pai foi removido e excluído. Desde o padrão C ++ 11 , uma solução foi adicionada usando ptr compartilhado e ptr fraco , herdado da biblioteca Boost .

Referências fracas também são usadas para minimizar o número de objetos desnecessários na memória, permitindo que o programa indique quais objetos são de menor importância referenciando-os apenas fracamente.

Variações

Alguns idiomas têm vários níveis de força de referência fraca. Por exemplo, Java tem, em ordem decrescente de força, referências suaves , fracas e fantasmas , definidas no pacote java.lang.ref . Cada tipo de referência tem uma noção associada de acessibilidade. O coletor de lixo (GC) usa o tipo de alcançabilidade de um objeto para determinar quando liberar o objeto. É seguro para o GC liberar um objeto que é suavemente alcançável, mas o GC pode decidir não fazer isso se acreditar que a JVM pode poupar a memória (por exemplo, a JVM tem muito espaço de heap não utilizado). O GC irá liberar um objeto de difícil alcance assim que o GC perceber o objeto. Ao contrário dos outros tipos de referência, uma referência fantasma não pode ser seguida. Por outro lado, as referências fantasmas fornecem um mecanismo para notificar o programa quando um objeto foi liberado (a notificação é implementada usando ReferenceQueues).

Em C #, as referências fracas são diferenciadas pelo fato de rastrearem a ressurreição do objeto ou não. Essa distinção não ocorre para referências fortes, pois os objetos não são finalizados se tiverem quaisquer referências fortes a eles. Por padrão, em C # a referência fraca não rastreia a ressurreição, o que significa que uma referência fraca não é atualizada se um objeto é ressuscitado; estas são chamadas de referências fracas curtas , e as referências fracas que rastreiam a ressurreição são chamadas de referências fracas longas .

Algumas linguagens sem coleta de lixo, como C ++ , fornecem funcionalidade de referência fraca / forte como parte do suporte a bibliotecas de coleta de lixo. A biblioteca Boost C ++ fornece referências fortes e fracas. É um erro usar ponteiros C ++ regulares como contrapartes fracas de ponteiros inteligentes porque tal uso remove a capacidade de detectar quando a contagem de referência forte foi para 0 e o objeto foi excluído. Pior ainda, não permite detectar se outra referência forte já está rastreando um determinado ponteiro simples. Isso introduz a possibilidade de ter dois (ou mais) ponteiros inteligentes rastreando o mesmo ponteiro simples (o que causa corrupção assim que a contagem de referência de um desses ponteiros inteligentes atinge 0 e o objeto é excluído).

Exemplos

As referências fracas podem ser úteis ao manter uma lista das variáveis ​​atuais sendo referenciadas no aplicativo. Esta lista deve ter links fracos para os objetos. Caso contrário, uma vez que os objetos são adicionados à lista, eles serão referenciados por ela e persistirão durante a duração do programa.

Java

Java 1.2 em 1998 introduziu dois tipos de referências fracas, uma conhecida como "referência suave" (destinada a ser usada para manter caches em memória gerenciados por GC, mas que não funciona muito bem na prática em algumas plataformas com heap dinâmico como o Android) e outro simplesmente como uma “referência fraca”. Ele também adicionou um mecanismo experimental relacionado apelidado de “referências fantasmas” como uma alternativa ao perigoso e ineficiente mecanismo finalize ().

Se uma referência fraca for criada e, em seguida, em outro lugar no código get()for usada para obter o objeto real, a referência fraca não é forte o suficiente para evitar a coleta de lixo, então pode ser (se não houver referências fortes para o objeto) que get()de repente começa a retornar nulo.

import java.lang.ref.WeakReference;

public class ReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        WeakReference r = new WeakReference("I'm here");
        StrongReference sr = new StrongReference("I'm here");
        System.out.println("Before gc: r=" + r.get() + ", static=" + sr.get());
        System.gc();
        Thread.sleep(100);

        // Only r.get() becomes null.
        System.out.println("After gc: r=" + r.get() + ", static=" + sr.get());
    }
}

Outro uso de referências fracas é escrever um cache . Usando, por exemplo, um mapa de hash fraco , pode-se armazenar no cache os vários objetos referidos por meio de uma referência fraca. Quando o coletor de lixo é executado - quando, por exemplo, o uso de memória do aplicativo fica suficientemente alto - os objetos em cache que não são mais referenciados diretamente por outros objetos são removidos do cache.

Conversa fiada

|a s1 s2|

s1 := 'hello' copy.     "that's a strong reference"
s2 := 'world' copy.     "that's a strong reference"
a := WeakArray with:s1 with:s2.
a printOn: Transcript. 
ObjectMemory collectGarbage.
a printOn: Transcript.  "both elements still there"

s1 := nil.              "strong reference goes away" 
ObjectMemory collectGarbage.
a printOn: Transcript.  "first element gone"

s2 := nil.              "strong reference goes away" 
ObjectMemory collectGarbage.
a printOn: Transcript.  "second element gone"

Lua

weak_table = setmetatable({}, {__mode="v"})
weak_table.item = {}
print(weak_table.item)
collectgarbage()
print(weak_table.item)

Objective-C 2.0

No Objective-C 2.0, não apenas a coleta de lixo, mas também a contagem automática de referência será afetada por referências fracas. Todas as variáveis ​​e propriedades no exemplo a seguir são fracas.

@interface WeakRef : NSObject
{
    __weak NSString *str1;
    __unsafe_unretained NSString *str2;
}

@property (nonatomic, weak) NSString *str3;
@property (nonatomic, unsafe_unretained) NSString *str4;

@end

A diferença entre weak( __weak) e unsafe_unretained( __unsafe_unretained) é que quando o objeto para o qual a variável apontada está sendo desalocado, o valor da variável será alterado ou não. weakalguns serão atualizados para nile unsafe_unretainedum permanecerá inalterado, como um ponteiro pendente . As weakreferências são adicionadas ao Objective-C desde o Mac OS X 10.7 "Lion" e iOS 5 , junto com o Xcode 4.1 (4.2 para iOS), e apenas ao usar ARC. As versões mais antigas do Mac OS X, iOS e GNUstep suportam apenas unsafe_unretainedreferências como fracas.

Vala

class Node {
    public weak Node prev; // a weak reference is used to avoid circular references between nodes of a doubly-linked list
    public Node next;
}

Pitão

>>> import weakref
>>> import gc
>>> class Egg:
...     def spam(self):
...         print("I'm alive!")
...
>>> obj = Egg()
>>> weak_obj = weakref.ref(obj)
>>> weak_obj().spam()
I'm alive!
>>> obj = "Something else"
>>> gc.collect()
35
>>> weak_obj().spam()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'spam'

Veja também

Referências

links externos

C ++

Java

PHP

Pitão