C# 内存不足时释放的动态变量?
背景 所以前提是我有一个类,它为数据提供一个属性C# 内存不足时释放的动态变量?,c#,.net,variables,memory-management,C#,.net,Variables,Memory Management,背景 所以前提是我有一个类,它为数据提供一个属性 class ExampleClass { string _largeCalculatedVariable = null; public string largeCalculatedVariable { get { if (_largeCalculatedVariable == null) { _largeCalculatedVar
class ExampleClass
{
string _largeCalculatedVariable = null;
public string largeCalculatedVariable
{
get
{
if (_largeCalculatedVariable == null)
{
_largeCalculatedVariable = LongRunningCalculate();
}
return _largeCalculatedVariable
}
}
}
该属性隐藏了这样一个事实,即如果数据尚未生成,则数据可能会动态计算数据,但如果数据之前已预先计算或计算,则会返回缓存值
问题
问题是可能会生成一个ExampleClass的大列表,如果我访问足够多的largeCalculatedVariable
,我可能会耗尽内存。由于我可以随时重新计算该值,有没有办法告诉.NET在需要内存时删除\u large calculated variable
注意:我感觉我可能在这里使用了错误的设计模式。您可以使用。它允许保留对某些数据的引用,但如果需要,它会告诉垃圾收集器声明该引用,这正是您想要的
弱引用允许垃圾收集器收集对象,同时仍允许应用程序访问该对象。如果您需要该对象,您仍然可以获得对它的强引用,并防止收集该对象
如果您使用的是.NET 4.0或更高版本,则可以使用该类,您可以将其设置为具有应存储多少数据的规则,并且如果该类已达到其限制,它将自行清除以腾出空间
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;
}
}
}
如果需要,还可以让ExampleClass
在释放对象时从缓存中取出项目以释放空间,这样做不会有太多额外的实现
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);
}
}
除了使用WeakReference和MemoryCache(后者可能是更好的选择)的出色答案之外,我想补充一点,使用类型
Lazy
。
这种类型已经解决了您可能遇到的任何并发问题。
有人可能会想:“我没有多线程,为什么我要在意?”
Lazy
string Lazy<string> _largeCalculatedVariable = null;//No need to set it to null but whatever you prefer
public string largeCalculatedVariable
{
get
{
if (_largeCalculatedVariable == null)
{
_largeCalculatedVariable = new Lazy<string>(()=>
{
_largeCalculatedVariable = LongRunningCalculate();
}
}
return _largeCalculatedVariable.Value
}
}
string Lazy\u largeCalculatedVariable=null//无需将其设置为null,但可以随意设置
公共字符串largeCalculatedVariable
{
得到
{
如果(_largeCalculatedVariable==null)
{
_largeCalculatedVariable=新的惰性(()=>
{
_largeCalculatedVariable=LongRunningCalculate();
}
}
返回_largeCalculatedVariable.Value
}
}
您的代码很奇怪。字符串已经是可空类型,您不能使用可空代码。您使用的是什么版本的.NET?4.0中的一些新功能正是针对这种情况的。@ChrisDunaway:这只是快速的伪代码我在实际代码中没有使用字符串,代码已编辑您可以自由接受任何答案,但不是@ScottChamberlain答案最合适?MemoryCache是WeakReferenceSide的抽象/实现注意:如果您有长期复杂的计算(或某种难以创建的对象)由于内存压力而将其删除可能不会对您整体有所帮助…创建复杂对象通常需要比最终对象消耗更多的内存/资源,因此,虽然您可能会找到一些不错的缓存解决方案,但请确保您确实从中获益。从32位切换到64位可能会以更便宜的方式解决问题…我不这么认为我想这正是OP想要的。Lazy
只是延迟实例化。MemoryCache
达到极限后它不会释放它。我同意你的观点。我只是给其他答案增加了一些价值,这些答案已经提到了他想要的东西:WeakReference和MemoryCacheI会投票给你,但我没有必要的代表。MemoryCache
是很适合一般问题,但仅仅因为我现有的代码是如何设置的,我认为WeakReference
更合适。@user3196468我重新编写了我的示例,使其更接近您当前的实现(还删除了一些错误)。
string Lazy<string> _largeCalculatedVariable = null;//No need to set it to null but whatever you prefer
public string largeCalculatedVariable
{
get
{
if (_largeCalculatedVariable == null)
{
_largeCalculatedVariable = new Lazy<string>(()=>
{
_largeCalculatedVariable = LongRunningCalculate();
}
}
return _largeCalculatedVariable.Value
}
}