Rambler's Top100
Главная
Новости
Статьи
Форумы
Книги
Коды
Сообщество
Блоги
О нас
 

Логин

Email:
  Пароль:

Войти
Зарегистрироваться
Забыл пароль

Поиск

 Искать :
 
Вперед

Книги по теме

Искать:
в:
Порядок:

Исходник

Автор:

Начинающий программист

 
Название:

Перехват события сборки мусора.

Дата: 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 }
Вернуться к списку исходников в категории Немного оффтопа
 
Наш Киев

Apartments for Rent

Rambler's Top100
Рейтинг@Mail.ru
Идея: Dimon aka Manowar Программирование: Dimon aka Manowar Дизайн: Dan Lebedev
Хостинг от компании Parking.ru
Карта сайта