当我使用 Socket.IO 时,为什么会出现错误“System.OutOfMemoryException"类型的未处理异常 [英] When I use Socket.IO, why I got an error An unhandled exception of type 'System.OutOfMemoryException'

查看:31
本文介绍了当我使用 Socket.IO 时,为什么会出现错误“System.OutOfMemoryException"类型的未处理异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I coded a program to get the screen shot and send to the server. Every time, I got a screenshot and turned into base64 then sent it using Socket.IO. (using 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次)并给我错误:

windowMonitorManager.MonitorScreen() is for return a base64 string. If I do not use client.getSocket().Emit("Shot", image), the program could run correct, but if I add this line, the program stop like 2 seconds(send nearly 80 times) and give me the error :

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

如果我不发送这么长的字符串,只是一个短字符串hello",它发送了 1600 次然后出现同样的问题.

If I do not send the string as long as this, just a short string "hello", it sends 1600 times then occurs the same problem.

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

Somebody knows how to debug this problem?

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

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

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

I try to test socket.Emit(), and find it has its limit.

比如我发送一个10000000的字符串,88次后,出现内存不足的问题.如果我发送一个5000000的字符串,170次后,出现同样的问题.

For example, I send a string of 10000000, after 88 times, it occurs the out of memory problem. If I send a string of 5000000, after 170 times, it occurs the same problem.

推荐答案

内存不足通常是当进程消耗的内存比默认系统允许的内存大得多(例如 32 位系统上的 2 GB)时抛出的异常,在64位系统上,它更高,但仍然受到一定的实际限制,它不是2^64的理论值,它因操作系统而异,也依赖于底层RAM,但足够大单个进程,现在这种情况可能由于多种原因发生:

Out of memory is mostly an exception thrown when the process consumes much larger memory than what is allowed by default system (like 2 GB on a 32 bit system), on a 64 bit system, it is higher, but is still bound by the certain practical limit, it's not the theory value of 2^64, it differs from OS to OS and is also dependent on underlying RAM, but is large enough for a single process, now this situation can happens due to multiple reasons:

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

  • Memory leak (most prominent), mostly associated with the unmanaged code calls, if there's a handle or memory allocation that is not de-allocated or freed, over a period of time it leads to huge memory allocation for a process and thus the exception, when system cannot map any more.

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

Managed code can too leak and I have done that, when objects gets continuously created and they are not de-referenced, i.e they are still reachable in GC context, so you can lead to this scenario, I have done this in my code :)

这不是空引用或损坏,因此在这种情况下进行直接堆栈跟踪几乎没有用,因为您每次可能会得到不同的堆栈,它就像进程的堆栈线程,当异常发生时,它主要是误导,所以不要尝试这种方式.一个线程的执行方法并不代表它会导致内存泄漏,不同的线程会有所不同.

This is not a null reference or a corruption, so taking direct stack trace will be of little use in this scenario, simply because you may get a different stack every time, it will be like the stack of the process threads, when exception happens and it would be mostly misleading, so do not try that way. Executing method of a thread doesn't mean it caused memory leak and it will be different for different threads.

如何调试:

可以采取一些简单的步骤来缩小范围,但在进行任何操作之前,请确保您的调试版本具有适用于所有加载的进程二进制文件的有效 pdb 文件.

Number of simple steps can be taken to narrow down, but before anything ensure that you have the debug version with valid pdb files for all the loaded binaries of the process.

  • 要了解是否存在泄漏,请通过任务管理器或最好通过 perfmon 监视进程工作集"、虚拟字节"计数器,因为它更准确,还提供可视化图表.

  • To know whether is it a leak, monitor process "working set", "virtual bytes" counters either via task manager or preferably via perfmon, since it is much more accurate, also it provides visual graph.

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

Now a leak is a leak, so steps like increasing address space in a 32 bit system to 3 GB in place of default 2 GB can only help for sometime, but perfmon will tell you if there's a stabilization point, like in few cases, process needs 2.2 GB of memory, so 2 GB by default is not enough but 3 GB in boot.config and UserVA setting for fine tuning 3 GB will help avoiding exception.

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

  • If you are using 64 bit system then that's not a worry point, but ensure that your binary is compiled for X64 or any CPU, a 32 bit binary will run as a WOW process and will have limitation on 64 bit system too.

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

Also try a small utility handles from sysinternals, running it mutliple times in a batch for a process will provide details of a leaking handle, in terms of number of handles like file, mutex etc allocated

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

Once you have confirmed a genuine leak, not a settings or configuration or system issue, then comes the memory profilers. In free ones, you get lot of information through free tools like windbg, umdh and leakdiag, they infact point you to exact stack trace which is leaking. umdh and leakdiag are both very good tools, they let you know the leaking function. Leakdiag is more exhaustive than UMDH, but for runtime heap UMDH is good enough

专业的内存分析器,例如:

Professional memory profilers like:

点内存 - http://www.jetbrains.com/dotmemory/

也非常好,我个人认为 Dot 内存更有帮助,它有助于快速指向泄漏的函数或类型,只要您有正确的符号文件,只需很少的努力.两者都有免费下载版本

are also very good, i personally find Dot memory much more helpful and it helps in quickly pointing to the leaking function or type, with little effort, provided you have correct symbol files. Both have free download version available

解决内存不足异常大多是一个渐进的迭代过程,因为这个过程可能隐藏在内部深处,每次执行都会泄漏一块内存,并使整个过程陷入瘫痪.如果您在使用特定工具时需要帮助,请告诉我,然后我们可以看看还可以做些什么来进一步调试问题.快乐调试

Mostly resolving out of memory exception is a gradual and iterative process, because this one could be hidden deep inside, leaking a chunk memory with every execution and bringing the complete process to knees. Let me know if you need help in using a specific tool, then we can see what more can be done to debug the issue further. Happy Debugging

这篇关于当我使用 Socket.IO 时,为什么会出现错误“System.OutOfMemoryException"类型的未处理异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆