【发布时间】: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