简体   繁体   English

如何阻止异步tcp .NET代码耗尽整个系统的资源

[英]How to stop asynchronous tcp .NET code from using up an entire system's resources

In some asynchronous tcp server code I have, occasionally an error occurs that causes the process to consume the entire system's memory. 在我拥有的一些异步tcp服务器代码中,偶尔会发生错误,导致该进程消耗整个系统的内存。 In looking at the logs, event viewer and some MS docs the problem happens if "the calling application makes Asynchronous IO calls to the same client multiple times then you might see a heap fragmentation and private byte increase if the remote client stops its end of I/O" which results in spikes in memory usage and pinning of System.Threading.OverlappedData struct and byte arrays. 在查看日志,事件查看器和某些MS文档时,如果“调用应用程序多次对同一客户端进行异步IO调用,那么您可能会看到堆碎片,并且如果远程客户端停止I的结尾,则私有字节会增加,就会发生问题。 / O”会导致内存使用量激增以及System.Threading.OverlappedData结构和字节数组的固定。

The KB article's proposed solution is to "set an upper bound on the amount of buffers outstanding (either send or receive) with their asynchronous IO." KB文章提出的解决方案是“设置具有异步IO的未处理缓冲区(发送或接收)的上限”。

How does one do this? 如何做到这一点? Is this referring to the byte[] that are sent into BeginRead? 这是指发送到BeginRead的byte []吗? So is the solution simply wrapping access byte[]'s with a semaphore? 那么解决方案是否只是用信号量包装访问字节[]呢?

EDIT: Semaphore controlled access to byte buffers or just having static sized pool of byte buffers are two common solutions. 编辑:信号量控制的对字节缓冲区的访问或仅具有静态大小的字节缓冲区池是两种常见的解决方案。 A concern I have that still remains is that when this async client problem occurs (maybe it's some weird network event actually) having semaphores or byte buffer pools will prevent me from running out of memory, but it does not solve the problem. 我仍然需要担心的是,当发生异步客户端问题时(实际上实际上是一些奇怪的网络事件),具有信号灯或字节缓冲池将阻止我的内存不足,但不能解决问题。 My pool of buffers will likely get gobbled up by the problem client(s), in effect locking correct function legitimate clients out. 我的缓冲区池很可能会被有问题的客户端吞噬,实际上将正确的功能锁定了合法的客户端。

EDIT 2: Came across this great answer . 编辑2:遇到了这个好答案 Basically it shows how to manually unpin objects. 基本上,它显示了如何手动取消固定对象。 And while asynchronous TCP code leaves pinning up to behind the scenes runtime rules, it might be possible to override that by explicitly pinning each buffer before use, then unpinning at the end of the block or in a finally. 而且,尽管异步TCP代码会固定在后台运行时规则,但有可能通过在使用之前显式固定每个缓冲区,然后在块的末尾或最后取消固定来覆盖它。 I'm trying to figure that out now... 我现在想弄清楚...

One way of addressing the problem is by pre-allocating buffers and other data structures used in async communications. 解决问题的一种方法是通过预分配异步通信中使用的缓冲区和其他数据结构。 If you preallocate on startup, there will be no fragmentation, since the memory will naturally reside in the same area of the heap. 如果在启动时进行预分配,则不会有碎片,因为内存自然会驻留在堆的同一区域中。

I recommend using ReceiveAsync / SendAsync APIs added to .Net 3.5 SP1, which allows you to cache or pre-allocate both the SocketAsyncEventArgs structure and the memory buffer stored in SocketAsyncEventArgs.Buffer property, unlike the older BeginXXX / EndXXX APIs which only allow caching or pre-allocating the memory buffer. 我建议使用添加到.Net 3.5 SP1中的ReceiveAsync / SendAsync API,该API允许您缓存或预分配SocketAsyncEventArgs结构和SocketAsyncEventArgs.Buffer属性中存储的内存缓冲区,这与较旧的BeginXXX / EndXXX API仅允许缓存或预分配内存缓冲区。

Using the old API also incurred significant CPU costs, because the API internally created Windows Overlapped I/O structures again and again. 使用旧的API还会产生大量的CPU成本,因为API在内部一次又一次创建了Windows Overlapped I / O结构。 In the new API this takes place within SocketAsyncEventArgs , and so by pooling these objects, the CPU cost is paid only once. 在新的API中,此操作在SocketAsyncEventArgs ,因此通过池化这些对象,CPU成本只需支付一次。

Regarding your update on pinning: pinning is there for a reason, namely to prevent GC from moving the buffer during defragmentation. 关于您的钉扎更新:钉扎是有原因的,即防止碎片整理期间GC移动缓冲区。 By unpinning manually, you may cause memory corruption. 通过手动取消固定,可能会导致内存损坏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM