取消固定.NET套接字服务器中自动固定的字节[]

我有一个异步套接字服务器。我遇到了一个问题,即有问题的客户端和难以重现的网络事件导致疯狂的字节数[]被锁定。由于所有处理客户端的线程都是隐式的(我使用BeginAcceptClient,我使用回调而不是显式实例化的线程),我不控制钉住过程。 “隐式线程”是指线程不是由我直接生成的,而是由托管我的应用程序的运行时生成的。

无论如何,文章中的答案显示了如何取消固定对象。如果我继续前进并自己固定字节[],是否可以重写幕后锁定,在清理期间执行BeginRead并取消锁定?

谢谢。

2
额外 编辑
意见: 1

2 答案

在你链接的帖子中的答案是完全错误的(我刚刚在那里留下了评论)。只有当最后一个钉住手柄(更一般:因为除GCHandles之外还有其他原因而钉住“原因”)被移除时,该对象才被解除锁定。你不能强制取消固定。这将是非常不安全的。你可以使用安全的托管代码来做不安全的事情,甚至是安全问题!

无论如何,尝试防止锁定物体是没有意义的。即使这是可能的,但事实并非如此,你的过程会随机崩溃!套接字依赖于锁定正确性。它没有理由不这样做。

解决方案在别处:

  1. 在应用程序启动时创建所有缓冲区,以便所有缓冲区在内存中保持连续。使用缓冲池。
  2. 使用少量大缓冲区并将其分配给各个客户端。

一个小方面的说明:固定与您的想法有所不同。固定不是可以在对象上打开和关闭的标志。当你固定一些东西时,一开始没有什么特别的事情发生。只有当GC运行时,GC才会注意到存在引用具有它们所固定的特殊属性的引用。然后它防止对象被移动。

4
额外
太好了,谢谢。
额外 作者 kmarks2,

我建议你不要专注于Pin/Unpin,而是从不同的AppDomain中完成所有套接字调用。然后,您可以在处于“闲置/安全”状态时卸载并重新加载该AppDomain,以将其中的内存重置为良好状态。

1
额外
他可以做一个手动GC来清除所有未使用的缓冲区。关闭一个appdomain不会添加任何有关GC的新功能。 GC是流程全球化的。
额外 作者 usr,
你假设有处理泄漏。 BCL套接字的实现当然没有,他也没有做任何固定。无论如何,关闭appdomain会断开套接字。
额外 作者 usr,
GC是流程全局的,但清除AppDomain将调用该域中项目的所有终结器;其中之一,希望可以在仍然持有缓冲区的GCHandle上调用Free。它取决于有问题的代码,但它可以释放GC在下一次扫描时收集的数组。
额外 作者 GWLlosa,
我同意;关闭appDomain将断开套接字。但是有人必须泄露一些东西;因为解锁别人固定的内存很困难/容易出错,我认为你可以得到的最接近的就是清除AppDomain,希望其他人能够更好地清理缓冲区。这是假设缓冲区不受你控制。
额外 作者 GWLlosa,