이것을 먼저 꺼내서 다시 보자.
약한 참조는 개체에 탭을 유지하려고 할 때 유용하지만 개체가 수집되는 것을 막기 위해 관찰을 원하지는 않습니다.
처음부터 시작하겠습니다.
의도하지 않은 공격에 대해서는 사전에 사과하지만, 잠재 고객에게 절대 말할 수 없기 때문에 잠시 동안 "Dick and Jane"수준으로 돌아가겠습니다.
따라서 객체를 얻었을 때 X
-인스턴스로 지정합시다 class Foo
-그 자체로는 살 수 없습니다 (대부분은 사실입니다). "아무도 섬이 아니다"와 같은 방식으로, 개체가 섬으로 승격 될 수있는 방법은 몇 가지뿐입니다. 비록 CLR에서 말하는 것은 GC 루트라고합니다. 기본적으로 GC 루트가되거나 GC 루트에 대한 연결 / 참조 체인이 설정되어있는 것이 기본적으로 Foo x = new Foo()
가비지 수집 여부를 결정합니다 .
힙이나 스택 워킹으로 GC 루트로 돌아갈 수 없다면 효과적으로 고아가되어 다음주기에 표시 / 수집 될 수 있습니다.
이 시점에서 끔찍하게 고안된 몇 가지 예를 살펴 보겠습니다.
먼저, 우리의 Foo
:
public class Foo
{
private static volatile int _ref = 0;
public event EventHandler FooEvent;
public Foo()
{
_ref++;
Console.WriteLine("I am #{0}", _ref);
}
~Foo()
{
Console.WriteLine("#{0} dying!", _ref--);
}
}
상당히 간단합니다-스레드 안전하지 않으므로 시도하지 마십시오. 그러나 활성 인스턴스 및 종료시 대략적인 "참조 수"를 유지합니다.
이제 보자 FooConsumer
:
public class NastySingleton
{
// Static member status is one way to "get promoted" to a GC root...
private static NastySingleton _instance = new NastySingleton();
public static NastySingleton Instance { get { return _instance;} }
// testing out "Hard references"
private Dictionary<Foo, int> _counter = new Dictionary<Foo,int>();
// testing out "Weak references"
private Dictionary<WeakReference, int> _weakCounter = new Dictionary<WeakReference,int>();
// Creates a strong link to Foo instance
public void ListenToThisFoo(Foo foo)
{
_counter[foo] = 0;
foo.FooEvent += (o, e) => _counter[foo]++;
}
// Creates a weak link to Foo instance
public void ListenToThisFooWeakly(Foo foo)
{
WeakReference fooRef = new WeakReference(foo);
_weakCounter[fooRef] = 0;
foo.FooEvent += (o, e) => _weakCounter[fooRef]++;
}
private void HandleEvent(object sender, EventArgs args, Foo originalfoo)
{
Console.WriteLine("Derp");
}
}
따라서 우리는 이미 GC 루트 인 객체를 가지고 있습니다 (자체적으로 구체적으로 말하면이 응용 프로그램을 실행하는 앱 도메인에 직접 체인을 통해 루팅되지만 두 가지 방법이 있습니다) Foo
인스턴스 에 래 칭하는 방법 -테스트 해 보겠습니다.
// Our foo
var f = new Foo();
// Create a "hard reference"
NastySingleton.Instance.ListenToThisFoo(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
이제, 위에서 언급 한 객체 f
가 "수집 가능" 할 것으로 예상 하십니까?
아니, 지금에 대한 참조를 잡고 또 다른 목적이 있기 때문에 - Dictionary
점에서 Singleton
정적 인스턴스입니다.
자, 약한 접근법을 시도해 봅시다.
f = new Foo();
NastySingleton.Instance.ListenToThisFooWeakly(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
// This should collect # 2 - you'll see a "#2 dying"
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
이제, 한 Foo
번에 한 번만 f
언급했던 객체에 대한 "하드"참조가 더 이상 없기 때문에 수집 WeakReference
할 수 있습니다.
좋은 사용 사례 :
이벤트 처리기 (이 내용을 먼저 읽으십시오 : C #의 약한 이벤트 )
"재귀 참조"를 유발하는 상황이 있습니다 (예 : 객체 A는 객체 B를 의미하며 객체 A는 "메모리 누수"라고도 함). (편집 : derp, 물론 이것은 사실이 아님)
객체 모음에 무언가를 "브로드 캐스트"하고 싶지만, 객체를 살아있는 것으로 유지하고 싶지는 않습니다. a List<WeakReference>
는 쉽게 유지 관리 할 수 있으며, 위치를 제거하여 정리할 수도 있습니다.ref.Target == null