记忆压力线人/计数器/统计

时间:2013-06-15 15:56:53

标签: c# wcf memory

我有一个应用程序可以在静态字段中保存/缓存许多对象。当在应用程序的生命周期中保存了大量对象时,由于缓存增长很大,因此会抛出内存不足异常。

是否有任何类或对象通知我内存已用完,并且将很快抛出outofmemoryexception以便我可以通过删除其中一些缓存对象来了解我需要释放一些内存?我正在寻找应用程序中存在内存压力的迹象,以便在引发内存异常之前我可以在应用程序运行时期间采取预防措施。

2 个答案:

答案 0 :(得分:0)

如果你有如此多的数据缓存,你的内存不足,表明你的缓存方法存在严重问题。即使是32位进程,您也有2 GB的地址空间。

您应该考虑使用有限的缓存,用户可以在其中设置首选缓存大小,并在达到此大小时自动删除对象。您可以实现某些缓存策略来选择要从缓存中删除的对象:最旧的对象或最不常用的对象或这些对象的组合。

您还可以尝试将一些缓存映射到磁盘,并仅将最常用的对象保留在内存中。当需要一个不在内存中的对象时,可以从磁盘反序列化它并将其放回内存中。如果某个对象在一段时间内未使用,则可以将其交换到磁盘。

答案 1 :(得分:0)

我还有一个应用程序尽可能多地使用ram。根据您的具体情况,您有几个选项(都有缺点)。

最简单的方法之一是预先分配您正在缓存的类(或字节)的循环缓冲区,以便预先使用所有ram。这通常不是首选,因为当你不需要时,消耗盒子上的所有RAM只是简单粗鲁。

处理大型缓存(或防止丢失内存异常)的另一种方法是在分配之前首先检查我需要的内存是否存在。这具有需要序列化存储器分配的缺点。否则,可用RAM检查和分配之间的时间可能会耗尽RAM。

以下是我在.NET中发现的最佳方法示例:

//Wait for enough memory
var temp = new System.Diagnostics.PerformanceCounter("Memory", "Available MBytes");
long freeMemory = Convert.ToInt64(temp.NextValue()) * (long)1000000;
long neededMemory = (long)bytesToAllocate;
int attempts=1200; //two minutes

while (freeMemory < neededMemory)
{
     //Signal that memory needs to be freed
     Console.WriteLine("Waiting for enough free memory:. Free Memory:" + freeMemory + " Needed Memory(MB):" + neededMemory);
     System.Threading.Thread.Sleep(100);
     freeMemory = Convert.ToInt64(temp.NextValue()) * (long)1000000;
     --attempts;

     if (0 == attempts)
          throw new OutOfMemoryException("Could not get enough free memory. File:" + Path.GetFileName(wavFileURL));
}

//Try and allocate the memory we need.

此外,一旦我在while循环中,我发出一些内存需要被释放的信号(取决于你的应用程序)。注意:我试图通过使用Sleep语句来简化代码,但最终您可能需要某种类型的非轮询操作。

我不确定您的应用程序的细节,但如果您是多线程的,或运行许多不同的可执行文件,那么在将内存分配给缓存时序列化此内存检查可能会更好。如果是这种情况,我使用信号量确保只有一个线程和/或进程可以根据需要分配RAM。与此类似:

Semaphore namedSemaphore = new Semaphore(1, 1, "MemoryAllocationSemaphore"); //named semaphores are cross process
     if (bytesToAllocate > 2000000) //if we need less than 2MB then dont bother locking.
     {
             if (!namedSemaphore.WaitOne((int)TimeSpan.FromMinutes(15).TotalMilliseconds))
             {
                throw new TimeoutException("Waited over 15 minutes for aquiring memory allocation semaphore");
             }
     }

稍后再说这个:

namedSemaphore.Release();

在finally块中释放信号量。

另一个选择是使用多个读取器单个写入器锁。让多个线程从缓存中提取数据(例如ReaderWriterLock类)。这样做的好处是,在您编写时可以检查内存压力和清理,然后向缓存添加更多内容,但仍有多个线程处理数据。缺点当然是将数据导入缓存的瓶颈来自单个固定点。