Мы столкнулись с проблемой управления ресурсами, с которой мы боролись в течение нескольких недель, и, хотя у нас наконец есть решение, оно все еще кажется мне странным.
У нас есть значительное количествокод взаимодействия, который мы разработали для унаследованной системы, которая предоставляет C API.Одна из многих особенностей этой системы заключается в том, что (по неизвестным причинам) «среда», которая, по-видимому, является областью действия, должна быть инициализирована до использования API.Тем не менее, он может быть инициализирован только один раз и должен быть «выключен», как только вы закончите с ним.
Мы первоначально использовали шаблон Singleton для достижения этой цели, но, поскольку мы используем эту систему внутри размещенной IISвеб-служба, наш AppDomain будет время от времени подвергаться переработке, что приведет к появлению «осиротевших» сред, в которых происходит утечка памяти.С момента завершения и (по-видимому) даже IIS-утилизации недетерминировано и трудно обнаружить во всех случаях, мы перешли на схему подсчета выбытия + реф, которая, кажется, работает хорошо.Тем не менее, делать подсчет ссылок вручную кажется странным, и я уверен, что есть лучший подход.
Есть мысли по управлению статическим глобальным одноразовым ресурсом в такой среде?
Вот примерная структураУправление окружающей средой:
public class FooEnvironment : IDisposable
{
private bool _disposed;
private static volatile int _referenceCount;
private static readonly object InitializationLock = new object();
public FooEnvironment()
{
lock(InitilizationLock)
{
if(_referenceCount == 0)
{
SafeNativeMethods.InitFoo();
_referenceCount++;
}
}
}
public void Dispose()
{
if(_disposed)
return;
lock(InitilizationLock)
{
_referenceCount--;
if(_referenceCount == 0)
{
SafeNativeMethods.TermFoo();
}
}
_disposed = true;
}
}
public class FooItem
{
public void DoSomething()
{
using(new FooEnvironment())
{
// environment is now initialized (count == 1)
NativeMethods.DoSomething();
// superfluous here but for our purposes...
using(new FooEnvironment())
{
// environment is initialized (count == 2)
NativeMethods.DoSomethingElse();
}
// environment is initialized (count == 1)
}
// environment is unloaded
}
}