1

我有一个应用程序可以在静态字段中保存/缓存许多对象。当在应用程序的生命周期中保存了大量对象时,由于缓存变得如此之大,会引发内存不足异常。

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

4

2 回答 2

0

如果您缓存的数据太多以至于内存不足,这表明您的缓存方法存在严重问题。即使作为 32 位进程,您也有 2 GB 的地址空间。

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

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

于 2013-06-15T16:33:24.737 回答
0

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

最简单的方法之一是预先分配一个循环缓冲区,其中包含要缓存的类(或字节),以预先消耗所有内存。这通常不是首选,因为当你不需要时消耗一个盒子上的所有 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类)。这样做的好处是,当您写入时可以检查内存压力和清理,然后将更多内容添加到缓存中,但仍然有多个线程处理数据。缺点当然是将数据放入缓存的瓶颈来自单个固定点。

于 2013-06-15T18:08:42.917 回答