Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 内存不足时释放的动态变量?_C#_.net_Variables_Memory Management - Fatal编程技术网

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);
    }
}

除了使用WeakReferenceMemoryCache(后者可能是更好的选择)的出色答案之外,我想补充一点,使用类型
Lazy
。 这种类型已经解决了您可能遇到的任何并发问题。 有人可能会想:“我没有多线程,为什么我要在意?”

  • 使用
    Lazy
  • 可伸缩性:一旦你想利用应用程序进行多线程处理,它已经准备好了
  • 从.NET4.0开始,我总是实现这样的延迟加载属性

    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
           }
       }