Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/301.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# 如何使用IDisposable修复内存泄漏_C#_.net_Garbage Collection - Fatal编程技术网

C# 如何使用IDisposable修复内存泄漏

C# 如何使用IDisposable修复内存泄漏,c#,.net,garbage-collection,C#,.net,Garbage Collection,我有一个.net应用程序似乎存在内存泄漏问题。net服务启动时大约有100MB的内存,但在负载下大约有400-500MB。我的大多数类都没有非托管资源,那些已经实现IDisposable的类。所以我的问题是在我的课堂上打IDisposable会有帮助吗 4-500 MB本身并不重要。问题是有8种不同的服务。每个都是使用SharpArch、NServiceBus、Windsor和NHibernate构建的。我的感觉是,其中一个问题是由某种东西引起的。我担心的是,所有服务的总内存大约是4 GB内存中

我有一个.net应用程序似乎存在内存泄漏问题。net服务启动时大约有100MB的内存,但在负载下大约有400-500MB。我的大多数类都没有非托管资源,那些已经实现IDisposable的类。所以我的问题是在我的课堂上打IDisposable会有帮助吗

4-500 MB本身并不重要。问题是有8种不同的服务。每个都是使用SharpArch、NServiceBus、Windsor和NHibernate构建的。我的感觉是,其中一个问题是由某种东西引起的。我担心的是,所有服务的总内存大约是4 GB内存中的3.2到3.6 GB。它还没有抛出OfMemory异常,但我想在关口阻止它。我还使用了dotTrace,它给了我一些信息,我只是不知道如何根据这些信息采取行动

更长的回答是:不


我想你已经知道了——如果你不知道,你就不会在需要它的类上“打”IDisposable——IDisposable与GC无关。这里唯一重要的是,如果您在对象上不必要地放置了终结器(~classname)——这将导致它们在获得GC之前备份到单线程终结器队列中,无论它们是否包含非托管资源。

如果所有具有非托管资源的类都实现了
IDisposable
,并且被正确地处置(通过使用或try/finally),那么进一步添加
IDisposable
实现将不会有任何帮助

第一个问题是,你不知道为什么你在泄漏。托管应用程序通常由于以下原因之一而泄漏

  • 未正确处置非托管资源
  • 保留托管对象的大型对象图
  • 根据你问题中的信息,几乎可以肯定是2造成了问题。您需要使用探查器或windbg来告诉您实际泄漏是什么,以及哪些根对象导致了泄漏

    下面是Rico写的一篇很棒的文章,让您开始学习


    • 答案是,几乎可以肯定不是。您是否通过分析您的服务来验证您实际上保留了不应该保留的内存


      请记住,垃圾收集器在需要释放内存之前不一定会释放内存,因此,它达到400-500mb的分配并不罕见。我所关心的问题是,在[在此插入合理的时间段]使用之后,它会进一步上升并达到1Gb,即使它没有处于任何更高的负载水平。

      我首先关心的是确保您正在测量相关的内容。“记忆”可以指很多不同的东西。耗尽虚拟内存空间和耗尽RAM之间存在巨大差异。翻动页面文件导致的性能问题与创建过多GC压力导致的性能问题之间存在巨大差异

      如果您不了解RAM、虚拟内存、工作集和页面文件之间的关系,那么就从阅读开始,直到您了解所有这些内容。你对这个问题的措辞让我怀疑你相信虚拟内存和RAM是一回事他们当然不是。

      我怀疑你正在做的算术是:

      • 我有八个进程,每个进程消耗5亿字节的虚拟地址空间
      • 我有40亿字节的内存
      • 因此,我将得到一个OutOfMemory异常
      这种三段论是完全无效的。这就是三段论:

      • 我有八夸脱冰淇淋
      • 冰箱里有九夸脱冰淇淋的空间
      • 因此,如果我再吃两夸脱冰淇淋,就会有东西融化
      事实上,你在隔壁有一个仓库大小的冷藏设施。记住,RAM只是一种方便快捷的方式,可以在你需要的地方储存东西,比如你的冰箱。如果你有更多的东西需要储存,谁会在乎你的房间是否用完了呢?你可以随时打开隔壁的门,把你不常使用的东西放在长期深度冻结中——页面文件。那不太方便,但什么都不会融化

      当进程耗尽虚拟地址空间时,而不是当系统中的所有RAM都用完时,会出现“内存不足”异常。当系统中所有的RAM都被消耗掉时,你不会得到一个错误,你会得到糟糕的性能,因为操作系统花费了所有的时间在磁盘上来回运行东西

      所以,不管怎样,首先要了解你在测量什么以及Windows中内存是如何工作的。您实际上应该寻找的是:

      • 在32位系统上,是否有任何进程有使用超过20亿字节虚拟内存的危险?一个进程在win32上只能获得2GB的虚拟内存(不是RAM,记住,虚拟内存与RAM无关:这就是为什么它被称为“虚拟”——它不是可由用户代码寻址的硬件;如果你尝试使用更多,你会得到一个OOM

      • 是否有任何进程有可能试图分配一个巨大的虚拟内存块,从而导致没有该大小的连续内存块可用?例如,您是否可能在单个阵列中分配一千万字节的数据?再一次,噢

      • 所有进程的工作集(即,出于性能原因*需要在RAM中的进程的虚拟内存页)是否小于可用RAM的数量?如果不是,那么很快你就会被揍,但不会被揍

      • 如果RAM开始变短,页面文件是否足够大以处理可能被分页到磁盘的虚拟内存页面

      到目前为止,这一切都没有什么意义