6

我用 C# 编写了一个长 TCP 连接套接字服务器。我的服务器中的内存出现峰值。我使用 dotNet Memory Profiler(一种工具)来检测内存泄漏的位置。Memory Profiler 显示私有堆很大,内存如下图(数字不是真实的,我想展示的是 GC0 和 GC2 的 Holes 非常非常大,数据大小正常):

  Managed heaps - 1,500,000KB 
          Normal heap - 1400,000KB 
              Generation #0 - 600,000KB 
                  Data - 100,000KB 
                  "Holes" - 500,000KB 
              Generation #1 - xxKB 
                  Data - 0KB 
                  "Holes" - xKB 
              Generation #2 - xxxxxxxxxxxxxKB 
                  Data - 100,000KB 
                  "Holes" - 700,000KB 
          Large heap - 131072KB 
              Large heap - 83KB 
              Overhead/unused - 130989KB 
          Overhead - 0KB

但是,什么是 GC 漏洞?dotNet Memory Profiler 的文档确定了“漏洞”:

“空洞”表示两个分配的实例之间未使用的内存。由于固定实例或垃圾收集器中的优化,当堆未完全压缩时会出现“空洞”。

我想知道的是:

  1. “洞”出现在哪两种分配的实例之间?
  2. 固定什么样的实例?
  3. 如何压缩堆?

我希望有人能解释一下。

4

1 回答 1

6

固定对象是不允许在内存中移动的对象。在使用非托管代码时通常需要这样做,这需要您传递指向内存中某个结构的指针 - 默认情况下,垃圾收集器可以自由移动该结构以最好地管理内存,但是如果它在您这样做时已经给一些非托管代码一个指向该结构的指针,那么如果它移动该非托管代码将不再指向正确的结构,从而导致意外行为。

解决方案是“固定”该对象以告诉 GC 它不应该移动它。

您不能显式压缩堆,GC 在执行完全或部分收集时应该这样做(除了LOH) - 固定大量对象将使其更难成功管理它。有关 GC 的更多详细信息,请参阅垃圾收集器基础知识和性能提示

于 2012-10-15T12:59:30.777 回答