소멸자에서 이벤트 핸들러를 제거해야 합니까?
는 약간의 를 사용합니다.UserControls
이 컨트롤이 있는 하위 창을 만들고 닫음으로써 런타임 중에 응용프로그램 내에서 생성 및 삭제됩니다.
은 WPF UserControl에서 것입니다.System.Windows.Controls.UserControl
.거기에는 없다Dispose()
내가 무시할 수 있는 방법.
PPMM
입니다.Singleton
내 지원서와 동일한 수명으로.
(에서 (WPF)는UserControl
이벤트 핸들러를 추가합니다.
public MyControl()
{
InitializeComponent();
// hook up to an event
PPMM.FactorChanged += new ppmmEventHandler(PPMM_FactorChanged);
}
소멸자에서 이러한 이벤트 핸들러를 제거하는 데 익숙해졌습니다.
~MyControl()
{
// hook off of the event
PPMM.FactorChanged -= new ppmmEventHandler(PPMM_FactorChanged);
}
오늘 저는 이것을 우연히 발견하고 다음과 같이 생각했습니다.
이것이 필요합니까?아니면 GC에서 처리합니까?
이게 효과가 있을까요?아니면 새로 생성된 데이터를 저장해야 합니까?ppmmEventHandler
?
당신의 답변을 기다리고 있겠습니다.
때부터PPMM
수명이 긴 개체(싱글톤)입니다. 그렇다면 이 코드는 그다지 의미가 없습니다.
여기서 문제는 해당 이벤트 핸들러가 개체를 참조하는 한 해당 이벤트를 소유한 다른 개체가 활성 상태인 한 가비지 수집에 적합하지 않다는 것입니다.
이와 같이, 파괴자에 무엇이든 넣는 것은 다음 중 하나와 같이 무의미합니다.
- 이벤트 핸들러가 이미 제거되었으므로 개체가 가비지 수집 대상이 되었습니다.
- 이벤트 핸들러가 제거되지 않았으며, 소유 개체는 가비지 수집에 적합하지 않으므로 피니시저가 호출되지 않습니다.
- 두 개체 모두 가비지 수집에 적합합니다. 이 경우 내부 상태를 모르기 때문에 피니시저에서 해당 다른 개체에 전혀 액세스하지 않아야 합니다.
요컨대, 이러지 마세요.
이제, 그러한 코드를 추가하는 것에 대해 다른 주장이 제기될 수 있습니다.Dispose
메드시를 할 때, 구현소.IDisposable
그런 경우에는 호출 중인 사용자 코드 때문에 완전히 의미가 있습니다.Dispose
미리 정의되고 제어된 지점에서.
그러나 피니시저(파괴자)는 객체가 가비지 수집에 적합하고 피니시저가 있는 경우에만 호출되며, 이 경우에는 의미가 없습니다.
제가 "그런 이벤트에서 구독을 취소할 수 있습니까?"라고 생각하는 nbr. 2번 질문에 대해서는, 그럼, 가능합니다.가입할 때 사용한 대리인을 유지해야 하는 유일한 시간은 익명 메서드 또는 람다 식을 중심으로 대리인을 구성할 때입니다.기존 방식을 중심으로 구성하면 작동합니다.
편집: WPF. 맞아요, 그 태그를 보지 못했습니다.죄송합니다, 제 나머지 답변은 WPF에 별로 의미가 없고 제가 WPF-guru이기 때문에 말씀드릴 수 없습니다.하지만, 이것을 고칠 수 있는 방법이 있습니다.SO에서는 개선할 수 있다면 다른 답변의 내용을 도용하는 것이 전적으로 합법입니다.WPF 사용자 제어를 사용하여 이 작업을 적절하게 수행하는 방법을 아는 사람이 있다면 제 답변의 전체 첫 번째 섹션을 자유롭게 들어 올리고 WPF의 관련 비트를 추가할 수 있습니다.
편집: 여기 안에 있는 댓글의 질문에도 답변을 드리겠습니다.
해당 클래스는 사용자 제어이므로 수명이 양식에 연결됩니다.양식이 닫힐 때 소유한 모든 하위 컨트롤을 삭제합니다. 즉, 여기에는 이미 삭제 방법이 있습니다.
사용자 컨트롤이 자체 이벤트를 관리하는 경우 이를 처리하는 올바른 방법은 Dispose 메서드에서 이벤트 핸들러의 후크를 해제하는 것입니다.
(받침대 제거)
먼저 파괴자를 사용하지 말고 폐기()를 사용하여 리소스를 삭제하십시오.
두 번째로, 제 생각에는 이 코드가 매우 자주 생성되고 수명이 짧은 개체 안에 있는 경우 이벤트 핸들러를 제거하는 것이 좋습니다. 이는 홀더 개체에 대한 링크이므로 GC가 이벤트 핸들러를 수집할 수 없습니다.
안부 전해요.
는 WPF를 지원하지 .IDisposable
정리가 필요한 WPF 제어를 구현하는 경우 대신 및 이벤트를 후크하는 것이 좋습니다(또는 추가).
즉은다이연에결다에서 이벤트에 합니다.Loaded
및결끊에서 및 Unloaded
핸러들 이 가 없고 많은할 수 있는 할 수 .물론 이 옵션은 컨트롤이 "로드"되지 않은 상태에서 이벤트를 수신할 필요가 없고 많은 로드/언로드 사이클을 올바르게 지원할 수 있는 경우에만 선택할 수 있습니다.
를 Loaded
/Unloaded
이벤트는 사용되는 모든 위치에서 사용자 컨트롤을 수동으로 삭제할 필요가 없다는 것입니다.하지만 당신은 그것을 알아야 합니다.Unloaded
응용 프로그램 종료가 시작된 후 이벤트가 발생하지 않습니다.예: 종료 모드가OnMainWindowClose
,Unloaded
다른 창의 이벤트는 실행되지 않습니다.하지만 이것은 보통 문제가 되지 않습니다.그것은 단지 당신이 안정적으로 일을 할 수 없다는 것을 의미합니다.Unloaded
응용 프로그램이 종료되기 전/종료되는 동안 발생해야 합니다.
코드가 파괴자에게 도달했다면 더 이상 문제가 되지 않습니다.
그것은 그것이 더 이상 어떤 사건도 듣지 않을 때에만 파괴될 것이기 때문입니다.
만약 그것이 여전히 사건들을 듣고 있었다면, 그것은 파괴되지 않았을 것입니다.
아이즈PPMM
더 긴 수명을 가진 외부 무언가.MyControl
예를 들면요?
만약 그렇다면, 그렇지 않다면PPMM_FactorChanged
방법,즉 정적 방법입니다.ppmmEventHandler
는 에대참유것입니다지할를조한▁to에 대한 할 것입니다.MyControl
instance live - 인스턴스가 가비지 수집에 적합하지 않고 최종 사용자가 실행되지 않음을 의미합니다.
당신은 그것을 보관할 필요가 없습니다.ppmmEventHandler
제거 코드에 대해 설명합니다.
GC가 처리할 것입니다.이벤트는 강력한 참조를 보유하지만 상위 개체 자체에만 유지됩니다.결국 MyControl만 이벤트 핸들러를 통해 참조를 유지하므로 GC가 이를 수집합니다.
반면에 설명자가 아닌 피니시저를 사용합니다.이 나쁜 관행 때문입니다. 등록을 취소하는 것을 .IDisposable
.
이벤트 핸들러는 까다롭고 리소스 누출을 쉽게 숨길 수 있습니다.티그란의 말대로.ID를 일회용으로 사용하고 소멸자는 잊어버립니다.당신이 맞았는지 측정하는 것을 추천합니다.작업 관리자에서 앱의 메모리 사용량을 보는 것만으로도 수천 개의 창을 로드하고 닫음으로써 약간의 스트레스 테스트를 수행하면 누출 여부를 알 수 있습니다.
이벤트 게시자가 구독 취소를 스레드 안전하게 보장하는 경우 Finalizer/Destrator의 이벤트에서 구독을 취소하는 것이 유용할 수 있는 경우가 있습니다.객체가 자체 이벤트에서 구독을 취소하는 것은 유용하지 않지만, 실행 가능한 패턴으로 공용 객체가 실제로 "모든 작업을 수행"하는 개인 객체에 대한 참조를 보유하고 해당 개인 객체가 이벤트에 구독하도록 할 수 있습니다.개인 개체에서 공용 개체로 되돌아오는 참조가 없는 경우, 공용 개체는 아무도 관심이 없으면 최종화 대상이 됩니다. 그러면 최종화자가 개인 개체를 대신하여 구독을 취소할 수 있습니다.
불행히도 이 패턴은 이벤트가 구독된 개체가 이벤트가 구독된 컨텍스트뿐만 아니라 모든 스레드 컨텍스트에서 구독 취소 요청을 수락할 수 있음을 보장하는 경우에만 작동할 수 있습니다..NET이 "이벤트" 계약의 일부로 모든 구독 취소 방법이 스레드 세이프여야 한다고 요구하는 것은 구현에 큰 부담을 주지 않았을 것이지만, MS는 어떤 이유로든 이러한 요구 사항을 부과하지 않았습니다.따라서 최종 사용자/파괴자가 이벤트를 가능한 한 빨리 구독 취소해야 한다는 것을 발견하더라도 이벤트를 실행할 수 있는 표준 메커니즘은 없습니다.
효과가 있습니다.
저는 (In-App 메시징 서비스를 통해) 릴리스되지 않은 글로벌 개체에 대한 이벤트 처리기를 사용하여 GC가 해당 개체를 수집할 수 없는 경우가 있었습니다.저는 이것이 보통 드문 조건이라고 생각합니다 - 레드 게이트의 ANTS와 같은 프로파일러를 사용하면 당신에게 이런 일이 일어난다고 생각한다면 쉽게 메모리 프로파일링을 할 수 있습니다.
언급URL : https://stackoverflow.com/questions/6663000/do-you-need-to-remove-an-event-handler-in-the-destructor
'programing' 카테고리의 다른 글
VB.NET에서 사용하는 방법? (0) | 2023.05.22 |
---|---|
LockModeType Jpa 간의 차이 (0) | 2023.05.22 |
다른 NoSQL 데이터베이스와 관련하여 DynamoDB의 장단점은 무엇입니까? (0) | 2023.05.17 |
명령줄을 사용하여 지정된 경로에서 node_modules 폴더를 재귀적으로 삭제합니다. (0) | 2023.05.17 |
Mac + virtualenv + pip + postgresql = 오류: pg_config 실행 파일을 찾을 수 없습니다. (0) | 2023.05.17 |