当我使用Socket.IO时,为什么会出现错误类型为' System.OutOfMemoryException'的未处理异常

时间:2014-09-16 17:33:47

标签: c# sockets socket.io

我编写了一个程序来获取屏幕截图并发送到服务器。每次,我都有截图并转入base64,然后使用Socket.IO发送。 (使用SocketIOClient.dll)

 Dictionary<string, string> image = new Dictionary<string, string>();
 image.add("image", "");

 private void windowMonitorTimer_Tick(object sender, EventArgs e)
 {

     image["image"] = windowMonitorManager.MonitorScreen();
     client.getSocket().Emit("Shot", image);
 }

windowMonitorManager.MonitorScreen()用于返回base64字符串。如果我不使用client.getSocket().Emit("Shot", image),程序可能运行正确,但如果我添加此行,程序停止2秒(发送近80次)并给我错误:

An unhandled exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll

如果我不发送字符串只要这个,只是一个短字符串“hello”,它发送1600次然后发生同样的问题。

有人知道如何调试这个问题吗?

/////////////////////////////////////////////// ////////////////////////////////////////////////// ////////////////////////////////////////////////// /////////////////////////

我尝试测试socket.Emit(),发现它有其限制。

例如,我发送一个10000000的字符串,经过88次,就会发生内存不足的问题。 如果我发送一个5000000的字符串,经过170次,就会出现同样的问题。

3 个答案:

答案 0 :(得分:1)

内存不足主要是一个例外,当进程消耗的内存比默认系统允许的内存大得多时(比如32位系统上的2 GB),在64位系统上,它更高,但仍然是绑定的根据一定的实际限制,它不是2 ^ 64的理论值,它不同于操作系统和OS,也依赖于底层RAM,但对于单个进程来说足够大,现在这种情况可能由于多种原因:

  • 内存泄漏(最突出),主要与非托管代码调用有关,如果没有解除分配或释放的句柄或内存分配,在一段时间内会导致大量内存当系统无法再映射时,进程的分配以及异常的分配。

  • 托管代码可能会泄漏而且我已经这样做了,当对象被连续创建并且它们没有被引用时,即它们仍然可以在GC上下文中访问,所以你可以导致这种情况,我已经完成了这在我的代码中:))

  • 这不是空引用或损坏,因此在这种情况下采用直接堆栈跟踪几乎没有用,只是因为每次都可能得到不同的堆栈,它就像进程的堆栈一样线程,当异常发生时,它将主要是误导,所以不要尝试这种方式。执行线程的方法并不意味着它会导致内存泄漏,并且对于不同的线程它会有所不同。

如何调试:

可以采取一些简单的步骤来缩小范围,但在此之前确保您拥有包含该进程所有已加载二进制文件的有效pdb文件的调试版本。

  • 要知道它是否是泄漏,监控过程&#34;工作集&#34;,&#34;虚拟字节&#34;通过任务管理器或最好通过perfmon进行计数,因为它更精确,也提供了可视化图形。

  • 现在泄漏是泄漏,所以将32位系统中的地址空间增加到3 GB代替默认2 GB的步骤只能帮助一段时间,但是perfmon会告诉你是否有&#sa; sa稳定点,就像在少数情况下,进程需要2.2 GB的内存,因此默认情况下2 GB不够,但boot.config中的3 GB和微调3 GB的UserVA设置将有助于避免异常。

    • 如果您使用的是64位系统,那么这不是一个担心点,但确保您的二进制文件是针对X64或任何CPU编译的,32位二进制文​​件将作为WOW进程运行并且将具有对64位系统的限制。

    • 还可以尝试sysinternals中的一个小实用程序句柄,在批处理中多次运行它一个进程将提供泄漏句柄的详细信息,就文件,互斥锁等分配的句柄数量而言

      < / LI>
    • 一旦确认了真正的泄漏,而不是设置或配置或系统问题,那么内存分析器就会出现。在免费工具中,你可以通过诸如windbg,umdh和leakdiag之类的免费工具获得大量信息,它们实际上指向了泄漏的精确堆栈跟踪。 umdh和leakdiag都是非常好的工具,它们让你知道泄漏的功能。 Leakdiag比UMDH更详尽,但对于运行时堆UMDH足够好

  • 专业内存分析器,如:

  • 点记忆 - http://www.jetbrains.com/dotmemory/

  • 蚂蚁 - 红门 - http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/

也非常好,我个人觉得Dot内存更有帮助,如果你有正确的符号文件,它可以帮助你快速指向泄漏的功能或类型,只需很少的努力。两者都有免费下载版本

主要解决内存不足异常是一个渐进和迭代的过程,因为这个过程可能隐藏在内部,每次执行都会泄漏大块内存并使整个过程陷入困境。如果您在使用特定工具时需要帮助,请告诉我们,然后我们可以看到还可以采取哪些措施来进一步调试问题。快乐调试

答案 1 :(得分:0)

听起来像SocketIOClient DLL中有一个错误。没有DLL我无法重现问题,但跟踪它听起来很容易。

由于C#是一种垃圾收集语言,因此获得内存不足(OOM)的唯一方法就是分配了太多无法追踪到“根对象”的内存。有几种根对象:

  • 静态变量(或threadstatic)
  • 堆栈跟踪中的方法变量(locals / arguments)

您从这两个对象(直接/间接)引用的所有对象都会导致您的记忆压力。如果你分配了不可用的内存,GC会在抛出OOM之前首先尝试释放内存;如果GC完成后没有足够的内存可用,则会抛出OOM。

可能发生这种情况的一个明显原因是因为您正在运行32位进程,这是目前Visual Studio中的默认进程。这可以在项目属性中修复。但是,大多数进程不需要超过2 GB的内存,因此您更有可能在某处泄露内存。所以让我们分解一下:

泄漏的本地人或参数

解决这类OOM的方法:

  1. 打开visual studio,ctrl d,e(或debug - &gt; exceptions)
  2. 点击OutOfMemoryException - &gt;检查'throw'框
  3. 运行程序。
  4. 当内存不足(OOM)命中时,浏览堆栈跟踪(或“并行堆栈”)中的节点并检查变量的大小。在大多数情况下,它是导致问题的单个缓冲区或集合。 F.ex.在你的情况下,缓冲区可能会填满套接字数据,而这些数据永远不会被清空。

    泄漏的静态变量

    OOM的其他情况通常是粒度填充并具有对主树的引用的缓冲区。找到这些的最简单方法是使用内存分析器,如Red Gate / ANTS内存分析器。在分析器中运行程序,拍摄一些快照并检查“大型实例”。

    一般来说,我通常会尽量避免使用静态变量,从而解决了整个问题。

    哦,在这种情况下......

    也许值得注意的是,有很多好的套接字库...尽管我不知道SocketIOClient的细节,但您可能需要考虑使用广泛支持的,经过验证的套接字库,如WCF / SOAP或Protobuf。关于如何在几乎所有场景中使用这些内容的网上有很多材料,所以如果问题出在SocketIOClient中,你可能会考虑......

答案 2 :(得分:0)

我猜你太频繁地运行你的计时器并将记忆力转移到不可持续的地步。你尝试降低它的频率吗?

如果降低频率没有帮助,您的代码或SocketIOClient.dll库可能会泄漏内存。我建议您首先查看该库的用法,以验证您是否未打开资源。