运行测试时特定计算机上的OutOfMemoryException

OutOfMemoryException on a particular machine when running tests
2021-06-10
  •  译文(汉语)
  •  原文(英语)

我们有一个NUnit测试的测试,该测试在特定计算机上遭受OutOfMemoryExceptions.

经过调查,看来这不是内存问题,而是句柄问题(我们分配了太多的Bitmap对象,而不释放它们).

问题是,它可以在一台特定的计算机上完美运行,而在另一台计算机上却出现此错误.

  1. 故障机器是具有Windows7 x64(6 GB内存)的Hyper-V VM
  2. 工作机是Windows XP(2 GB内存)的物理机

我知道最好的解决方案是清理代码以处理任何Bitmap对象,但是我想知道为什么这两台机器在执行同一代码时在行为上会有所不同?

速聊1:
嗯,.NET框架可能是相同的,但底层OS却不同.诸如位图之类的资源仍由操作系统处理.Windows 7处理资源的方式与Windows XP不同,因此在不同版本的Windows上获得不同的结果也就不足为奇了.
速聊2:
Windows拒绝再发出之前可以泄漏的句柄数量是可配置的.也许其中一台机器的配置不同.
速聊3:
谢谢@eric.你知道这可以从哪里控制吗?
速聊4:
-acid:这是一个问答网站.提问题为问题!
解决过程1

阅读此:http : //blogs.technet.com/b/markrussinovich/archive/2010/02/24/3315174.aspx

您将找到一张表格,其中列出了Windows的不同版本之间相对于GDI堆的区别.简短的答案:XP = 3Mb限制,Win7R2x64 = 20Mb限制.可用RAM无关紧要,这些是硬性限制.

速聊1:
这与以下事实无关:在XP上不会崩溃,在Win7上会崩溃:(
速聊2:
本来可以宣誓就职的条件与现在相反
解决过程2

这不太可能,Windows允许您先泄漏10,000个句柄,然后再对程序的运行方式感到不满意,并拒绝让您分配更多的句柄.到那时,您已经为位图中的像素数据消耗了大量的虚拟内存空间.存储在非托管内存中,垃圾收集器不知道它.除非您调用Dispose()或垃圾收集器通过运行终结器来处理它,否则不会释放VM空间.

GC通常无法完成工作,Bitmap类是一个很小的对象,不足以单独触发GC.您必须分配其中的60,000个来触发GC.您将永远无法到达那里,除非位图非常小,否则首先会用完VM空间,然后再处理.调用Dispose()是可选的,但是对于位图而言,它不再是可选的,因为终结器无法及时完成工作.

RAM的大小对此没有任何影响,.NET程序总是在上面轰炸,无法在VM地址空间中找到足够大以适合请求的大小的空位.位图也是一个问题,它们往往需要大孔.它只需要将一个DLL加载到一个笨拙的基地址中,即可将一个不错的大漏洞切成两半.否则,很容易解决问题,只需将程序的目标平台设置为AnyCPU.测试程序为此具有一个配置值.在该Win7机器上工作.但是,当然,这不是跳过Dispose()调用的正当理由.

We have a test of NUnit tests that are suffering OutOfMemoryExceptions on a particular machine.

After investigation it seems that it is not a memory issue, but a Handle issue (we are allocating too many Bitmap objects and not releasing them).

The issue is, that this runs perfectly on a particular machine, while failing with this error on another one.

  1. Failing machine is a Hyper-V VM with Windows7 x64 (6 GB ram)
  2. Working Machine is a physical machine Windows XP (2 GB ram)

I know that the best solution would be to clean up the code to dispose of any Bitmap objects, but i am interested in knowing why do these 2 machines differ in behavior when executing the same code?

Talk1:
Well, the .NET framework may be the same, but the underlying OS isn't. Resources like bitmaps are still handled by the operating system. Windows 7 handles resources differently than Windows XP does, so it is not surprising that you get different results on different versions of Windows.
Talk2:
The number of handles that can leak before Windows refuses to issue any more is configurable. Perhaps one of the machines is configured differently.
Talk3:
Thanks @eric. Do u know where this can be controlled from ?
Talk4:
-acid: This is a question and answer site. Ask the question as a question!
Solutions1

Read this: http://blogs.technet.com/b/markrussinovich/archive/2010/02/24/3315174.aspx

You will find a table of the differences between various versions of Windows with respect to GDI heap. Short answer: XP = 3Mb limit, Win7R2x64 = 20Mb limit. Free RAM doesn't matter, these are hard limits.

Talk1:
This doesn't go with the fact that on XP it doesn't crash and on the Win7 it does :(
Talk2:
Could have sworn your conditions were the reverse of the way they are now
Solutions2

That's unlikely, Windows allows you to leak 10,000 handles before it gets cranky about the way your program behaves and refuses to let you allocate more. By then you've consumed massive amounts of virtual memory space for the pixel data in the bitmaps. Stored in unmanaged memory, the garbage collector is unaware of it. VM space that doesn't get released unless you call Dispose() or the garbage collector takes care of it by running the finalizer.

The GC doesn't typically get the job done, the Bitmap class is a very small object, not big enough to trigger a GC by itself. You'd have to allocate about 60,000 of them to trigger a GC. You'll never get there, you'll run out of VM space first unless the bitmaps are very small, handles next. Calling Dispose() is optional, but that stops being optional for bitmaps since the finalizer just can't get the job done in time.

The amount of RAM plays no role in this whatsoever, a .NET program always bombs on it not being able to find a hole in the VM address space that's big enough to fit the requested size. Also an issue with bitmaps, they tend to need big holes. It just takes a DLL that gets loaded at an awkward base address to cut a nice big hole into two. Otherwise a problem that's easily solved, just set the target platform of the program to AnyCPU. A test program has a configuration value for that. Works on that Win7 machine. But of course, that's not a valid reason to skip the Dispose() calls.

转载于:https://stackoverflow.com/questions/19095551/outofmemoryexception-on-a-particular-machine-when-running-tests

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入