什么是“异步固定句柄”?
我正在尝试调查一个非常严重的软件崩溃,这可能与托管堆损坏有关(因为它发生在垃圾收集期间)。使用 WinDbg 和 (SOS) !gchandles 命令我得到类似的东西
0:000> !gchandles
GC Handle Statistics:
Strong Handles: 259
Pinned Handles: 137
Async Pinned Handles: 1
Ref Count Handles: 79
Weak Long Handles: 197
Weak Short Handles: 650
Other Handles: 0
Statistics:
我只是好奇,“正常”固定句柄和“异步固定”句柄之间有什么区别?我能找到我的哪个句柄是“异步”句柄吗? 我在网上找不到任何有关它的信息,因为当该计数器恰好为 1 时,应用程序似乎总是崩溃,因此可能与崩溃有关。但话又说回来,它可能只是垃圾收集期间使用的一些内部东西。
I'm trying to investigate a really nasty software crash which is possibly related to a managed heap corruption (since it happens during a garbage collection). Using WinDbg with the (SOS) !gchandles command I get something like
0:000> !gchandles
GC Handle Statistics:
Strong Handles: 259
Pinned Handles: 137
Async Pinned Handles: 1
Ref Count Handles: 79
Weak Long Handles: 197
Weak Short Handles: 650
Other Handles: 0
Statistics:
And I'm just curious, what is the difference between a "normal" pinned handle and an "async pinned" one? And can I find which one of my handles is the "async" one?
I couldn't find any information on the net about it and since it seems that the application always crashes when this counter is exactly one it might be relevant to the crash. But then again it might just be some internal stuff used during the garbage collection..
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
异步固定句柄与 Windows 中的重叠 I/O 密切相关。它支持使用 ReadFile 和 WriteFile 进行异步读取和写入,并使用 OVERLAPPED 参数。设备驱动程序存储传递的缓冲区指针,并直接从缓冲区读取/写入缓冲区,完全与程序操作异步。托管包装方法是 BeginRead 和 BeginWrite。
如果缓冲区是在 GC 堆中分配的,则需要将其固定,直到驱动程序完成使用缓冲区。让 GC 在驱动程序处理 I/O 传输时移动缓冲区是灾难性的,写入会产生垃圾,读取会损坏 GC 堆,需要固定以防止在驱动程序处理 I/O 传输时移动缓冲区司机正在使用它。
固定的物体非常令人不快,当垃圾收集器压缩堆时,它们使垃圾收集器很难在道路上的岩石周围工作。这里有一个必要的罪恶,唯一可能的方法就是让缓冲区固定尽可能短的时间。
异步固定句柄经过专门标记,以允许 CLR 在 I/O 完成时自动取消固定缓冲区。当 I/O 完成端口发出完成信号时尽快,因此不必等待客户端代码执行回调并取消固定缓冲区。当有大量正在运行的线程池线程时,这可能需要一段时间。当您拥有处理数万个客户端请求的 Web 服务器时,这是一种微观优化,往往会变成宏观优化。
它仅用于 System.Threading.OverlappedData 类型的对象,这是 mscorlib.dll 中的一个内部类,CLR 对它有专门的了解,并且是 Windows api 函数使用的本机 OVERLAPPED 结构的托管传真。
长话短说,您真正知道的是,如果您在崩溃时看到句柄计数为 1,则有一个重叠的 I/O 待处理。拥有任何与 gc 分配的未固定缓冲区重叠 I/O 的本机代码确实是销毁堆的好方法。顺便说一句,你有很多固定的手柄。
Async pinned handles are strongly correlated with overlapped I/O in Windows. Which supports asynchronous reading and writing with ReadFile and WriteFile, using the OVERLAPPED argument. The device driver stores the passed buffer pointer and directly reads/writes from/to the buffer, entirely asynchronously from the program's operation. The managed wrapper methods are BeginRead and BeginWrite.
If the buffer is allocated in the GC heap then it needs to be pinned until the driver finishes using the buffer. Having the GC move the buffer while the driver is working on the I/O transfers is disastrous, writes would produce junk and reads would corrupt the GC heap, pinning is required to prevent the buffer from being moved while the driver is using it.
Pinned objects are pretty unpleasant, they give the garbage collector a hard time to work around the rock in the road when it compacts the heap. A necessary evil here, the only possible way to get ahead is to leave the buffer pinned for as short amount of time as possible.
Async pinned handles are marked specially to allow the CLR to automatically unpin the buffer on I/O completion. As quickly as possible, when the I/O completion port signals completion and thus not having to wait for the client code to execute the callback and unpin the buffer. Which could take a while when there are lots of threadpool threads in flight. It is a micro-optimization that tends to turn into a macro one when you have, say, a web server that handles tens of thousands of client requests.
It is only ever used for objects of type System.Threading.OverlappedData, an internal class in mscorlib.dll that the CLR has special knowledge of and is the managed facsimile for the native OVERLAPPED structure that the Windows api functions use.
Long story short, all you really know is that there's an overlapped I/O pending if you see the handle count at 1 when it crashes. Having any native code that does overlapped I/O with gc allocated buffers that are not pinned is otherwise indeed a good way to destroy the heap. You have rather a lot of pinned handles btw.