我编写了一个程序来获取屏幕截图并发送到服务器。每次,我都有截图并转入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次,就会出现同样的问题。答案 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足够好
专业内存分析器,如:
也非常好,我个人觉得Dot内存更有帮助,如果你有正确的符号文件,它可以帮助你快速指向泄漏的功能或类型,只需很少的努力。两者都有免费下载版本
主要解决内存不足异常是一个渐进和迭代的过程,因为这个过程可能隐藏在内部,每次执行都会泄漏大块内存并使整个过程陷入困境。如果您在使用特定工具时需要帮助,请告诉我们,然后我们可以看到还可以采取哪些措施来进一步调试问题。快乐调试
答案 1 :(得分:0)
听起来像SocketIOClient
DLL中有一个错误。没有DLL我无法重现问题,但跟踪它听起来很容易。
由于C#是一种垃圾收集语言,因此获得内存不足(OOM)的唯一方法就是分配了太多无法追踪到“根对象”的内存。有几种根对象:
您从这两个对象(直接/间接)引用的所有对象都会导致您的记忆压力。如果你分配了不可用的内存,GC会在抛出OOM之前首先尝试释放内存;如果GC完成后没有足够的内存可用,则会抛出OOM。
可能发生这种情况的一个明显原因是因为您正在运行32位进程,这是目前Visual Studio中的默认进程。这可以在项目属性中修复。但是,大多数进程不需要超过2 GB的内存,因此您更有可能在某处泄露内存。所以让我们分解一下:
泄漏的本地人或参数
解决这类OOM的方法:
当内存不足(OOM)命中时,浏览堆栈跟踪(或“并行堆栈”)中的节点并检查变量的大小。在大多数情况下,它是导致问题的单个缓冲区或集合。 F.ex.在你的情况下,缓冲区可能会填满套接字数据,而这些数据永远不会被清空。
泄漏的静态变量
OOM的其他情况通常是粒度填充并具有对主树的引用的缓冲区。找到这些的最简单方法是使用内存分析器,如Red Gate / ANTS内存分析器。在分析器中运行程序,拍摄一些快照并检查“大型实例”。
一般来说,我通常会尽量避免使用静态变量,从而解决了整个问题。
哦,在这种情况下......
也许值得注意的是,有很多好的套接字库...尽管我不知道SocketIOClient的细节,但您可能需要考虑使用广泛支持的,经过验证的套接字库,如WCF / SOAP或Protobuf。关于如何在几乎所有场景中使用这些内容的网上有很多材料,所以如果问题出在SocketIOClient中,你可能会考虑......
答案 2 :(得分:0)
我猜你太频繁地运行你的计时器并将记忆力转移到不可持续的地步。你尝试降低它的频率吗?
如果降低频率没有帮助,您的代码或SocketIOClient.dll库可能会泄漏内存。我建议您首先查看该库的用法,以验证您是否未打开资源。