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. weak
alguns serão atualizados para nil
e unsafe_unretained
um permanecerá inalterado, como um ponteiro pendente . As weak
referê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_unretained
referê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
- Goldshtein, Sasha; Zurbalev, Dima; Flatow, Ido (2012). Desempenho do Pro .NET: Otimize seus aplicativos C # . Apress. ISBN 978-1-4302-4458-5.
links externos
C ++
-
Biblioteca padrão C ++ 11 :
std::weak_ptr
referência -
Boost 1.59 (biblioteca C ++) :
boost::weak_ptr
referência
Java
- Artigo do desenvolvedor Java: 'Objetos de referência e coleta de lixo'
- Nicholas, Ethan (4 de maio de 2006). "Compreendendo as referências fracas" . java.net . Arquivado do original em 03/03/2011 . Recuperado em 1 de outubro de 2010 .
- RCache - Biblioteca Java para cache baseado em referência fraca / suave
- Teoria e prática Java: conectando vazamentos de memória com referências fracas
PHP
Pitão
- https://docs.python.org/3/library/weakref.html
- Fred L. Drake, Jr., PEP 205: Weak References , Python Enhancement Proposal, janeiro de 2001.