Os manipuladores de eventos impedem a coleta de lixo?

183

Se eu tiver o seguinte código:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;

O pClass será coletado como lixo? Ou ele continuará disparando seus eventos sempre que eles ocorrerem? Preciso fazer o seguinte para permitir a coleta de lixo?

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;
Mark Ingram
fonte
11
Tentarei sugerir aos leitores interessados ​​nesta pergunta que talvez valha a pena se familiarizar com eventos leves / padrões de eventos fracos, que NÃO impedem a coleta de lixo. Uma boa inicialização de SO para este tópico é stackoverflow.com/questions/185931/…
fostandy
20
Nota para a posteridade: definir a referência como nulo simplesmente atrasa o coletor de lixo estendendo por uma linha o escopo da referência. .NET não é VB6.
John Saunders

Respostas:

207

Para a pergunta específica "O pClass será coletado de lixo": a assinatura do evento não afeta a coleta do pClass (como o editor).

Para o GC em geral (em particular, o destino): depende se MyFunction é estático ou baseado em instância.

Um delegado (como uma assinatura de evento) para um método de instância inclui uma referência à instância. Então, sim, uma assinatura de evento impedirá o GC. No entanto, assim que o objeto que publica o evento (pClass acima) é elegível para coleta, isso deixa de ser um problema.

Observe que isso é unidirecional; ou seja, se tivermos:

publisher.SomeEvent += target.SomeHandler;

o "editor" manterá o "alvo" ativo, mas o "alvo" não manterá o "editor" ativo.

Portanto, não: se o pClass for coletado de qualquer maneira, não há necessidade de cancelar a inscrição dos ouvintes. No entanto, se pClass foi longa vida (mais do que a instância com MyFunction), então pClass poderia manter essa instância vivo, por isso iria ser necessário cancelar a inscrição se deseja que o alvo a ser coletado.

Eventos estáticos, no entanto, por esse motivo, são muito perigosos quando usados ​​com manipuladores baseados em instância.

Marc Gravell
fonte
6
Bem, se a pergunta for "a classe será coletada como lixo", a resposta "depende se ..." não está correta. Não depende de nada, como o próprio Marc observa mais adiante.
Tor Haugen
@Tor - é justo - vou esclarecer
Marc Gravell
Embora um delegado de inscrição de evento aponte apenas uma maneira, um assinante com a intenção de cancelar a inscrição de um evento quando terminar com ele precisará de alguma forma de referência ao editor. Poderia ser uma WeakReference, e em alguns casos, uma boa ideia, mas sempre que não for forte.
supercat
Uma ótima resposta, pois também aborda a outra metade da pergunta (que não foi feita): o editor impedirá que o assinante seja submetido ao GC.
Bob Sammers
Sim, e como o @BobSammers disse, pode realmente ser um problema se uma instância de vida curta, como um Form / Window, estiver assinando um serviço de longa vida como um Singleton que fornece dados, por exemplo: o Singleton mantém uma referência , e os objetos são mantidos na memória, mesmo quando pensamos que eles estão descarregados! Portanto, tenha muito cuidado ao usar eventos. Abusamos de eventos para o nosso grande software, e é muito difícil resolver depois.
Elo
9

Sim, o pClass será coletado como lixo. A assinatura do evento não implica que exista qualquer referência a pClass.

Portanto, você não precisará desanexar o manipulador para que o pClass seja coletado.

Tor Haugen
fonte
8

No momento em que um pedaço de memória não é mais referenciado, ele se torna um candidato à coleta de lixo. Quando a instância da sua classe sai do escopo, ela não é mais referenciada pelo seu programa. Não é mais usado e, portanto, pode ser coletado com segurança.

Se você não tem certeza se algo será coletado, faça a si mesmo a seguinte pergunta: ainda existe uma referência a ele? Os manipuladores de eventos são referenciados pela instância do objeto, e não o contrário.

lvaneenoo
fonte
0

pClassserá coletado lixo. No entanto, se o trecho de código acima é dentro de outra classe, a instância dessa classe pode não ser apagada se você não definir pClassa null.

Arav
fonte