Background
So the premise is that I have a class that provides data with a property.
class ExampleClass
{
string _largeCalculatedVariable = null;
public string largeCalculatedVariable
{
get
{
if (_largeCalculatedVariable == null)
{
_largeCalculatedVariable = LongRunningCalculate();
}
return _largeCalculatedVariable
}
}
}
The property hides the fact that the data may calculate the data on the fly if it hasn't been generated yet but will return a cached value if it has been precalculated or calculated before.
Problem
The problem is that a large list of ExampleClass may be generated and if I access the largeCalculatedVariable on enough of them I may run out of memory. Since I can recalculate the value at any time is there a way to tell .NET to drop _largeCalculatedVariable when it needs memory?
Note: I have a feeling I maybe using the wrong design pattern here.
If you are using .NET 4.0 or newer you can use the MemoryCache class, you can set it to have rules of how much data it should store and it will clear itself out to make room if it has hit it's limit.
class ExampleClass
{
//This is a static constructor;
static ExampleClass()
{
var settings = new NameValueCollection();
settings.Add("PhysicalMemoryLimitPercentage", "75");
_cache = new MemoryCache("ExampleClassCache", settings);
}
private static MemoryCache _cache;
public ExampleClass()
{
_cacheKey = Guid.NewGuid().ToString();
}
private readonly string _cacheKey;
public string largeCalculatedVariable
{
get
{
var record = _cache.Get(_cacheKey) as string;
//If record was null that means the item was not in the cache.
if(record == null)
{
record = LongRunningCalculate();
_cache.Add(_cacheKey, record, new CacheItemPolicy(), null);
}
return record;
}
}
}
If you wanted you could also have ExampleClass take items out of the cache to free up space when the object is disposed, it would not be much extra to implement.
class ExampleClass : IDisposable
{
//...Everything else is the same from the previous code example.
public void Dispose()
{
Dispose(true)
GC.SupressFinialize(this);
}
bool _disposed;
protected virtual void Dispose(bool disposing)
{
if(!_disposed)
{
if(disposing)
{
//Nothing to do here, we want to remove from the cache if Dispose or the finalizer is called.
//But you may have IDisposeable objects in your real class, they should be disposed in here.
}
if(_cacheKey != null)
_cache.Remove(_cacheKey, null);
_disposed = true;
}
}
~ExampleClass()
{
Dispose(false);
}
}
You can use WeakReference. It allows to keep a reference to some data but tells the Garbage Collector to claim that reference if it needs to, which is exactly what you want.
A weak reference allows the garbage collector to collect an object while still allowing an application to access the object. If you need the object, you can still obtain a strong reference to it and prevent it from being collected.
_data = new WeakReference("Hamster");
return _data.IsAlive ? data.Target : CreateData();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With