【问题标题】:Too many Pinned Objects causing OutOfMemoryException太多固定对象导致 OutOfMemoryException
【发布时间】:2014-04-26 08:48:13
【问题描述】:

我们在仪器上有一个用 .Net/C# 3.5 Compact Framework 编写的应用程序。 我们正在使用Windows Compact Embedded 7 操作系统。

这个应用程序在很大程度上从设备中读取一些数据并将其存储在磁盘或 SD 卡上的文件中并显示 以图形/数字方式的数据。

要读取数据,我们通过以下方式传递一个字节数组来调用驱动程序。

[System.Runtime.InteropServices.DllImport("coredll.dll")]
         private static unsafe extern bool ReadFile(
                                               IntPtr hFile,
                                               byte* lpBuffer,
                                               uint nNumberOfBytesToRead,
                                               uint* lpNumberOfBytesRead,
                                               uint lpOverlapped);



public int Read(byte[] buffer, int index, int count)
         {
              uint temp;
              unsafe
              {
                   fixed (byte* pByte = &(buffer[index]))
                   {
                        if (!ReadFile(handle, pByte, (uint)count, &temp, 0)) 
                        {
                            return -1;
                        }
                   }
              }

              return (int)temp;
         }

而我们在单独线程中运行的 read 方法看起来像这样。

private void Reader()
{
  try
{
while(true)
{
byte[] data = new byte[1024*10];
Read(data,0,data.Length);
// Do something with data
}
}
catch(Exception ex)
{
}
}

我们的要求是应用程序应该连续运行几个月。

我在instrumnet 上启用了性能监视器,当我运行应用程序时,停止它并查看性能监视器生成的统计文件,我看到我们有数百万个固定对象,最终可能会导致内存泄漏。

这是统计文件。

counter                                           total   last datum            n       mean        min        max
Total Program Run Time (ms)                    60240358            -            -          -          -          -
App Domains Created                                   1            -            -          -          -          -
App Domains Unloaded                                  2            -            -          -          -          -
Assemblies Loaded                                    16            -            -          -          -          -
Classes Loaded                                     2466            -            -          -          -          -
Methods Loaded                                     9685            -            -          -          -          -
Closed Types Loaded                                 598            -            -          -          -          -
Closed Types Loaded per Definition                  598            1           61          9          1         97
Open Types Loaded                                    16            -            -          -          -          -
Closed Methods Loaded                               184            -            -          -          -          -
Closed Methods Loaded per Definition                184            3           55          3          1         13
Open Methods Loaded                                   1            -            -          -          -          -
Threads in Thread Pool                                -            9           19          6          1          9
Pending Timers                                        -            0      1986882          0          0          4
Scheduled Timers                                 662294            -            -          -          -          -
Timers Delayed by Thread Pool Limit                   0            -            -          -          -          -
Work Items Queued                                662294            -            -          -          -          -
Uncontested Monitor.Enter Calls                30435505            -            -          -          -          -
Contested Monitor.Enter Calls                        72            -            -          -          -          -
Peak Bytes Allocated (native + managed)        10869964            -            -          -          -          -
Managed Objects Allocated                     386020616            -            -          -          -          -
Managed Bytes Allocated                     25202701076           16    386022691         65          8    1048588
Managed String Objects Allocated               39325752            -            -          -          -          -
Bytes of String Objects Allocated            3041772660            -            -          -          -          -
Garbage Collections (GC)                          24644            -            -          -          -          -
Bytes Collected By GC                       25218571932       936288        24644    1023314      49132    1528716
Managed Bytes In Use After GC                         -      6162292        24644    5988047     235620    6162292
Total Bytes In Use After GC                           -     10729796        24644   10045775    2113544   10729796
GC Compactions                                    24640            -            -          -          -          -
Code Pitchings                                        1            -            -          -          -          -
Calls to GC.Collect                                   0            -            -          -          -          -
GC Latency Time (ms)                             532689           23        24644         21          4        103
**Pinned Objects                                   846589**            -            -          -          -          -
Objects Moved by Compactor                     15728750            -            -          -          -          -
Objects Not Moved by Compactor                261474730            -            -          -          -          -
Objects Finalized                              14917931            -            -          -          -          -
Objects on Finalizer Queue                            -            0     14944139        303          0       2546
Boxed Value Types                              17838485            -            -          -          -          -
Process Heap                                          -         5968    101947181     156314        336     209656
Short Term Heap                                       -            0      4050880         51          0      79952
JIT Heap                                              -            0        27236     895917          0    1861844
App Domain Heap                                       -         1536        29669     960504       1536    1297080
GC Heap                                               -            0          208    4088477          0    7512064
Native Bytes Jitted                             3495028          136         8431        414         84     111248
Methods Jitted                                     8431            -            -          -          -          -
Bytes Pitched                                   1738556          164         4269        407         72     111248
Methods Pitched                                    4269            -            -          -          -          -
Method Pitch Latency Time (ms)                       78           78            1         78         78         78
Exceptions Thrown                                   171            -            -          -          -          -
Platform Invoke Calls                           9528151            -            -          -          -          -
COM Calls Using a vtable                              0            -            -          -          -          -
COM Calls Using IDispatch                             0            -            -          -          -          -
Complex Marshaling                              1929605            -            -          -          -          -
Runtime Callable Wrappers                             0            -            -          -          -          -
Socket Bytes Sent                                   784            -            -          -          -          -
Socket Bytes Received                              1934            -            -          -          -          -
Controls Created                                    255            -            -          -          -          -
Brushes Created                                 3022728            -            -          -          -          -
Pens Created                                    1888616            -            -          -          -          -
Bitmaps Created                                  166286            -            -          -          -          -
Regions Created                                      19            -            -          -          -          -
Fonts Created                                        31            -            -          -          -          -
Graphics Created (FromImage)                          0            -            -          -          -          -
Graphics Created (CreateGraphics)                    23            -            -          -          -          -

在互联网上阅读后,我发现/理解在 Read 方法中,我们将有一个固定对象,但当我们退出 Read 方法时,它应该再次取消固定。

除了上述代码之外,我们没有任何其他代码与非托管环境交互。

我正在寻找解决固定对象问题的建议,有没有其他方法/工具可以帮助我们找到那些固定对象到底是什么。

还有其他更好的方法来进行这种托管/非托管通信吗?

【问题讨论】:

  • 固定缓冲区实际上并没有固定,你还没有找到真正的原因。 150 万个对象的终结器队列看起来很糟糕,我会先尝试诊断终结器线程停止运行的原因。
  • @HansPassant:“固定”语句设置一个指向托管变量的指针,并在语句执行期间“固定”该变量。执行语句中的代码后,所有固定变量都将取消固定并进行垃圾回收。发布的代码对我来说看起来不错。可能是您没有正确关闭文件句柄吗?
  • @HansPassant:我们如何诊断 Finalizer 线程停止的原因?有什么可用的工具,有什么建议吗?
  • @Simon - 这很荒谬,我几乎总是跟进我发布的答案。我有很多,比大多数 SO 用户多得多,充满了信息。这个问题无法回答,我所能做的就是给 OP 一个提示。如果您希望我停止给出提示,那么恐怕我无法满足您的要求。如果 OP 需要知道如何使用调试器对终结器线程进行故障排除,那么他应该问 that 问题。
  • @HansPassant 我不是说你的答案.. 他们太棒了。您似乎在没有跟进的情况下放弃了随机 cmets。当然,你是否回应完全取决于你。我只是想我会毫无恶意地指出我的观察结果。

标签: c# .net compact-framework windows-ce


【解决方案1】:

我认为计数器是指系统在 GC 期间发现处于固定状态的对象的数量。如果读取调用可能需要很长时间,这可能会经常发生。另一方面,我认为您可以轻松地减少应用程序执行的内存分配次数,只需将数据缓冲区的分配移到 while 循环之外。如果它的大小是固定的(从代码中可以看出),或者至少很容易确定最大大小,那么在每次迭代时重新分配它是没有意义的。您将旧的标记为 gc 并获取新的内存。您将达到最大内存阈值并且 gc 将启动。我不知道您的应用程序运行了多长时间,但分配 3.86 亿个对象看起来是一个很大的数字。避免无用的重新分配(例如您发布的代码中的重新分配)并使用 StringBuffers 代替字符串,例如,可以减少内存分配的数量,防止 GC 过于频繁地运行,并且通常可以提高您的代码效率。

【讨论】:

  • 我已将缓冲区的初始化移出 while 循环,但我仍然得到固定对象,我怎样才能找出导致固定对象的原因?
  • 至少它应该减少 GC 运行的次数...要找到固定问题,您可以尝试注释掉部分代码(如果您有多个线程,您可以尝试不旋转一些其中),试图找到产生问题的部分。您也可以尝试使用 GC 堆查看器的 CLR 分析器来尝试更好地了解您的应用程序如何管理内存。拥有 GC 并不意味着您不会遇到与内存相关的问题。
  • 即使我只调用了 Read 方法,我仍然有很多固定对象。
  • 我想 固定 objs 的数量与对 Read 的调用次数相匹配。即使您将缓冲区分配移到循环之外,对吗?
  • 是的,不是读取调用的确切数量,而是大约。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 2013-06-14
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
相关资源
最近更新 更多