【问题标题】:Asynchronouos Socket Communication & Heap fragmentation异步套接字通信和堆碎片
【发布时间】:2013-11-27 00:28:16
【问题描述】:

我编写了一个多线程套接字服务器应用程序,它接受超过 1000 个并发连接。最近我们遇到了应用程序崩溃;分析转储文件后得知应用程序由于堆损坏而崩溃。我发现以下链接中讨论了相同的问题。

.NET Does NOT Have Reliable Asynchronouos Socket Communication? http://support.microsoft.com/kb/947862

还讨论提出了 3 个解决方案。

  1. 网络应用程序应该对其发布的优秀异步 IO 的数量有一个上限。

  2. 使用 Microsoft CCR

  3. 使用 TPL

由于时间因素,我想坚持#1,但我不清楚如何实现这一点。有人可以给出一个好的起点吗?

还有没有人使用 Async with TPL 来解决这个问题?

【问题讨论】:

    标签: sockets async-await heap-memory asyncsocket


    【解决方案1】:

    您的意思是比您提到的答案中的blog posting that I linked to 更好的起点?

    问题是这样的:

    • 在异步写入期间使用的内存和其他每次操作资源通常处于“使用中”,直到远程对等方的 TCP 堆栈确认数据并且本地堆栈可以完成您的异步写入操作以告诉您可以重用您的缓冲区。
    • 本地对等方无法对此进行控制,因为这完全取决于远程对等方从其套接字读取数据的速度以及两个对等方之间的链路拥塞情况。

    由于上述原因,您需要对在任何时候未完成的异步写入数量进行硬性限制。您可以通过在发出异步写入之前增加一个计数器并在完成处理程序中减少它来跟踪这一点。

    一旦达到这个限制,你会做什么取决于你自己。在原始文章中,我倾向于将要写入的数据放入队列。当写完成发生时,这个队列可以用作数据源。一旦队列为空,您可以再次正常发送。当然,这只是解决了问题——您仍然拥有由远程对等方控制的内存资源(排队数据),但您也没有使用其他操作系统资源(非分页池、I/O 页面锁定限制、等)。

    当您达到限制时,您可以简单地停止您的对等发送 - 现在您通过异步 API 构建的 API 需要从之前的发送返回“暂时无法发送,稍后再试”过去总是“工作”。

    如果您这样做,我也会认真考虑通过在一个连续块中分配一大块缓冲区并从池中使用它们来避免固定内存问题。

    【讨论】:

    • 事实上,WCF 使用 BufferManager 正是出于这个原因。复制工作解决方案永远不会受到伤害
    【解决方案2】:

    首先,这是一篇非常古老的知识库文章。你怎么确定你有那个特殊的问题? 然后,正如 Hans Passant 在 SO 问题中回答的那样,如果你编写了糟糕的异步代码,它咬你。如果你不关心你的资源(内存缓冲区也是资源),并发程序面临内存错误

    使用原始线程编写好的并发代码非常困难,而 TPL 确实使它更容易,但它不会修复您已经存在的错误。事实上,除非您确定当前的问题,否则您很可能会将它们转移到使用 TPL 的版本。

    在不知道导致你的应用崩溃的具体问题的情况下,我只能提一些建议:

    1. 使用BufferManager 重用内存缓冲区而不是分配新的缓冲区。
    2. 使用队列来存储请求并异步处理它们,而不是为每个请求启动一个新线程。

    您还可以使用其他技术,具体取决于您正在构建的应用程序的类型。例如,您可以使用 TPL DataFlow 以独立步骤中断处理。

    至于 CCR,在 Robotics Studio 之外使用它没有多大意义。 TPL 包含编写并发应用程序所需的大部分相关功能。

    【讨论】:

      猜你喜欢
      • 2012-09-22
      • 2019-11-07
      • 2010-09-19
      • 2012-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-14
      • 2012-08-20
      相关资源
      最近更新 更多