|
|
|
 |
 |
Исходник |
 |
|
 |
 |
|
Автор:
|
|
|
Название:
|
Перехват события сборки мусора. |
|
Дата:
|
18 October 2006 |
|
Описание: |
Появляется иногда необходимость в каком-нибудь буфере, а System.Web.Caching или Enterprise Library использовать не хочется. Вот и рисуют люди свои кеши, да только как часто их чистить? Неплохой сигнал к действию -- сборка объектов поколения 0. Вот класс, который позволяет навесить обработчик на это событие.
З.Ы. Класс потокобезопасный. Класс нужно использовать как синглетон. Класс не поддерживает воскрешение (resurrection) и я его еще не тестировал (поэтому и выложил :). Collect будет вызываться на произвольной нитке, причем не на нитке GC. Класс может пропускать некоторые сборки мусора но не будет вызвать Collect, пока не завершился предыдущий вызов (по крайней мере так задумывалось). Я попытался минимизировать размеры и количество блокировок, а также кол-во сообщений в очереди ThreadPool-а, вот что получилось: |
| |
Разместить ссылку на этот исходник в форуме вы можете вставив в текст сообщения
следующую строку:
[CODEPOST ID=197]Перехват события сборки мусора.[/CODEPOST] |
| Оценить: |
|
1 sealed class GCHook
2 {
3 public GCHook()
4 {
5 __SyncRoot = this;
6 }
7
8 ~GCHook()
9 {
10 Finalized = true;
11 }
12
13 public event EventHandler<EventArgs> Collect
14 {
15 add
16 {
17 lock (SyncRoot)
18 {
19 __Collect += value;
20 EnsureBait();
21 }
22 }
23 remove
24 {
25 lock (SyncRoot)
26 __Collect -= value;
27 }
28 }
29
30 public object SyncRoot
31 {
32 get
33 {
34 return __SyncRoot;
35 }
36 }
37
38 private event EventHandler<EventArgs> __Collect;
39 private bool __Collecting;
40 private bool __Finalized;
41 private readonly object __SyncRoot;
42 private bool __HasBait;
43
44 private bool Collecting
45 {
46 get
47 {
48 return __Collecting;
49 }
50 set
51 {
52 __Collecting = value;
53 }
54 }
55
56 private bool Finalized
57 {
58 get
59 {
60 return __Finalized;
61 }
62 set
63 {
64 __Finalized = value;
65 }
66 }
67
68 private bool HasBait
69 {
70 get
71 {
72 return __HasBait;
73 }
74 set
75 {
76 __HasBait = value;
77 }
78 }
79
80 private void EnsureBait()
81 {
82 // мы не хотим создавать наживку до окончания сборки...
83 if (!HasBait && (!Collecting) && (__Collect != null))
84 {
85 new Bait(this);
86 HasBait = true;
87 }
88 }
89
90 private void GCCollectCallback(object obj)
91 {
92 if (!Finalized) // т.к. сообщение могло долго лежать в очереди, проверим актуальность действия еще раз...
93 try
94 {
95 OnCollect((EventArgs)obj);
96 }
97 finally
98 {
99 Thread.MemoryBarrier(); // удостоверимся, что процесс сборки завершился до создания новой наживки.
100 Collecting = false;
101 lock (SyncRoot)
102 EnsureBait();
103 }
104 }
105
106 private void OnCollect(EventArgs e)
107 {
108 EventHandler<EventArgs> collect = __Collect;
109 if (collect != null)
110 lock (SyncRoot)
111 collect(this, e);
112 }
113
114 private sealed class Bait
115 {
116 public Bait(GCHook hook)
117 {
118 __Hook = hook;
119 }
120
121 ~Bait()
122 {
123 GCHook hook = Hook;
124 if (!hook.Finalized)
125 {
126 hook.Collecting = true;
127 Thread.MemoryBarrier(); // нам важно, чтобы hook.Collecting проставилось до hook.HasBait, чтобы предотвратить создание наживки в процесе сборки мусора.
128 hook.HasBait = false;
129 Thread.MemoryBarrier(); // удостоверимся, что GCHook извещен о потере наживки до вызова его методов.
130 try
131 {
132 ThreadPool.QueueUserWorkItem(hook.GCCollectCallback, EventArgs.Empty);
133 }
134 catch
135 { // в случае, если не удалось отправить сообщение GCHook, создаем новую наживку самостоятельно и маскируем исключение.
136 lock (hook.SyncRoot)
137 {
138 hook.Collecting = false;
139 hook.EnsureBait();
140 }
141 }
142 }
143 }
144
145 public GCHook Hook
146 {
147 get
148 {
149 return __Hook;
150 }
151 }
152
153 private readonly GCHook __Hook;
154 }
155 } |
| Вернуться к списку исходников в категории Немного оффтопа |
|
|
 |
 |
 |
 |
|
|