【问题标题】:.net memory is not reclaimed.net 内存未回收
【发布时间】:2015-11-02 09:20:25
【问题描述】:

我有一个在 x64 机器上以“服务器 gc 模式”运行的“服务”(owin/webapi + odp.net 托管)。执行测试套件后,内存使用量约为 2Gb。我在那台机器上“产生”了内存压力(另一个程序消耗了所有可用内存等等)。我期待 Windows 会强制 .net 释放一些内存。然而它没有。这是windbg的输出:

0:018> !dumpheap -stat
Statistics:
              MT    Count    TotalSize Class Name
00007ffd10445b90        1           24 System.Collections.Generic.GenericEqualityComparer`1[[System.UInt64, mscorlib]]
...
00007ffd0f904918   100864     11616976 System.Object[]
0000005b19face20       84   1810674044      Free
Total 720544 objects
Fragmented blocks larger than 0.5 MB:
            Addr     Size      Followed by
0000005b1c3c8800  425.6MB 0000005b36d56c50 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005c1c3fcf00   28.2MB 0000005c1e02be58 System.Reflection.Emit.MethodBuilder
0000005c1e02e5b0  268.0MB 0000005c2ec313d8 System.Threading.OverlappedData
0000005c2ec31678  142.3MB 0000005c37a830a0 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005d1c541aa0  404.8MB 0000005d35a1a958 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005d35a1e5a8    3.8MB 0000005d35df0c40 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005e1cfe7128  444.1MB 0000005e38c0c3f0 System.Byte[]
0000005e38c8cfb8    4.5MB 0000005e39110988 System.Byte[]
0000005e39111bf8    1.2MB 0000005e3923a570 System.Byte[]
0000005e3923b7e0    0.7MB 0000005e392ed7d0 System.Byte[]
0000005e392eea40    1.1MB 0000005e39401910 System.Byte[]

0:018> !heapstat
Heap             Gen0         Gen1         Gen2          LOH
Heap0       455256040           24           24      3713672
Heap1       464550872           24      4327776       727456
Heap2       428541352     10344768        12616           24
Heap3       474250128           24     21350456           24
Total      1822598392     10344840     25690872      4441176

Free space:                                                 Percentage
Heap0       446429064            0            0      1819552SOH: 98% LOH: 48%
Heap1       459823968            0          144          152SOH: 98% LOH:  0%
Heap2       428520936        34904           24           24SOH: 97% LOH:100%
Heap3       474044952            0          336           24SOH: 95% LOH:100%
Total      1808818920        34904          504      1819752

所以只有大约 48Mb 实际使用和 1.8Gb 空闲,大部分内存不在 LOH 中,而是在 Gen 0 堆中,但 .net 不会归还该内存。同时系统正在缺乏内存。例如 IIS 无法启动,因为没有足够的内存。

为什么内存没有被windows回收?

【问题讨论】:

  • 只有 4GB 内存的服务器?
  • 16,但还有其他服务。我写道,我通过运行另一个占用所有可用内存的工具来模拟高内存压力
  • 请先阅读问题。它不是 IIS,不是 SQL。如果您想知道,Oracle 正在另一个城市的数据中心的 linux 服务器上运行。我有运行多项服务的专用服务器,其中一项会消耗所有内存并且不会放弃。我可以在更大的数据集上运行我的测试并占据整个 16Gb。问题是只使用了 50Mb,而 .net 捕获 2Gb 并没有将其返回给操作系统。
  • 几乎 1 GB 的 Func<IAsyncResult, HttpListenerContext> 委托对象是不正常的。很难想象可以做到这一点的代码。伴随异步 I/O 的典型对象锁定很可能会炸毁 GC。
  • 服务正在从 oracle 读取大结果。 10 列和 800K 行。因此,在读取数据库的响应时实际上使用了很多内存(存储结果的实现效率极低)。发送响应后,触发 gc 并回收内存。由于服务根据official documentation 在“服务器”模式下工作,因此“临时段”的大小为 2Gb,服务器服务正在运行。所以我想.net 不会将该段的一部分提供给操作系统。这听起来像真的吗?

标签: .net garbage-collection


【解决方案1】:

由于 Windows 无法强制应用释放对象。您需要找到一种方法来定义应用的最大内存使用量,并在达到最大限制时通过 GC.Collect() 手动调用垃圾收集器。

在应用程序运行时,尝试获取进程并设置maxLimit,类似于this

【讨论】:

    【解决方案2】:

    Windows 不能“强制”.Net 释放内存。虽然我不是 .Net 运行时方面的专家,但我的经验是,一旦您的应用程序开始消耗大量内存,.net 框架就会保留内存。它会在它认为合适的时候慢慢地把它还给它。从 Windows 的角度来看,它并不真正知道 .Net 会用它做什么,但它 .Net 声称来自操作系统的内存,因此在它(.net)将其归还之前,Windows 无法将该内存提供给另一个应用程序。有几个 400+mb 的 System.Byte[] 块被保留,这可能表示内存泄漏。从操作系统的角度来看,框架已经请求了内存,甚至使用了该内存,所以直到它被明确地(从框架而不是你)给回窗口之前,它不能做任何事情。我会非常仔细地分析您的应用程序,因为通常.Net 不释放内存的原因是因为您有内存泄漏。使用 Visual Studio 中的内存分析工具应该会显示您是否将内存“固定”或仅保留它。真正糟糕的罪魁祸首通常是静态类变量/事件。

    链接:.NET Free memory usage (how to prevent overallocation / release memory to the OS)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多