如何在不耗尽所有系统内存的情况下使 .NET 进程耗尽内存
问题很简单我有一个流程,对一些 xml 文件进行 ETL。 我们开始获取非常大的 xml 文件,并且我开始遇到 OutOfMemoryExceptions。
修复过程相对简单。 但是,我想对我的 NUnit 套件进行单元测试,以确保该进程继续能够处理非常大的文件。 然而,实际上,我的开发工作站上的内存不足会降低我的机器的速度,并且非常耗时。 在版本控制中存储巨大的测试文件也是一个坏主意。 如果我可以人为地限制进程、线程或应用程序域仅使用固定数量的 RAM(例如 128 兆),我可以进行较小的单元测试,而不会导致我的工作站崩溃。
有什么建议么? 我可以 P/Invoke 他们的一些非托管 API 吗?
The problem is simple I have a process, that does ETL on some xml files. We started getting really large xml files and I started getting OutOfMemoryExceptions.
Fixing the process is relatively simple. However, I'd like to make a unit test for my NUnit suite to make sure the process will continue to be able to handle really large files. However, actually running out of memory on my development workstation slows down my machine, and is time consuming. Storing a humongous test file in version control is also a bad idea. If I could artificially limit a process, thread or appdomain to only use a fixed amount of ram, lets say 128 megs, I could make a smaller unit test that would not bring my workstation, to its knees.
Any suggestions? Is their some unmanaged API I can P/Invoke?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您不能使用模拟框架进行内存分配并让它抛出 OutOfMemoryException 作为测试之一吗?
尽管如此,如果您确实内存不足,您的应用程序就无法安全地执行太多操作,但如果您至少可以优雅地失败,您的用户将会感激不已。
示例:
我之前的工作中有一个案例,我们需要实时显示工厂的 3D 模型。 模型变得如此之大,以至于当我们尝试加载纹理时,我们会遇到内存故障。 我们通过确保代码处理空指针来设法保持应用程序的活动和渲染,即使代码的其余部分认为那里应该有纹理信息。
Can't you use a mocking framework for the memory allocation and have it throw
OutOfMemoryException
as one of the tests?Having said that though, if you really have run out of memory there's not much your application can safely do, but if you can at least fail gracefully your users will be grateful.
An example:
I had a case in a previous job where we were displaying 3D models of factories in real-time. The models grew so large that when we tried to load textures we'd get out of memory failures. We managed to keep the application alive and rendering by making sure that the code coped with null pointers even though the rest of the code thought that there should be texture information there.
嘲笑是最好的。 实际上,根据定义,引发 OOM 并不是单元测试。 当处理内存时,您正在处理负载测试。 如果您阅读本电子邮件底部的链接,您会发现即使在最好的情况下,真正的 OOM 也很难重现和调试。 人为的 OOM 异常并不是异常的真正原因,因此并不比用于测试的模拟更有趣。
坚持使用模拟进行单元测试进行验证。 如果仍然遇到 OOM,请在服务器上投入更多内存,并使进程更频繁地回收/重新启动。
这是我上次与 OutMemoryExceptions 斗争时收集的一些关于 OutMemoryExceptions 的有趣读物。 摘要: 当系统无法分配您请求的数量时,就会发生 OOM——这并不意味着内存不足。
Mocking is best. Actually raising an OOM is by defininition not a unit test. When dealing with memory, you are dealing with load testing. If you read the links at the bottom of this email, you'll find real OOMs are dastardly hard to reproduce and debug in the best of cases. A contrived OOM exception is not the true cause of the exception, and thus no more interesting than a mock for testing.
Stick with a unit test using a mock for validation. If you still get OOMs, throw more memory on your server and make your process recycle/ restart more often.
Here is some interesting reading on OutMemoryExceptions I collected the last time I fought with them. Summary: OOMs occur when the system can't allocate the amount that you requested - which doesn't mean you are out of memory.
我不太明白你在这里得到什么。 假设您以某种方式创建了一个人为的小型“测试环境”,该环境无法分配同样大的内存块,因此它会在较小的文件上抛出 OutOfMemoryExceptions。 你得到了什么? 单元测试应该测试您是否可以在真实系统上处理更大的文件,对吗?
重要的是,您可以在文件将要运行的任何系统上处理“所需大小的文件”,并且除了在该系统上尝试该文件之外,没有真正的方法对其进行单元测试。
(一个更小、不太重要的事情可能是你是否优雅地处理
OutOfMemoryException
s,但你不需要实际耗尽内存来测试它;只需让你的方法偶尔抛出一个异常并观察它是否做了正确的事情。)I don't quite understand what you're getting at here. Let's suppose that somehow you created an artificially small "test environment" that couldn't allocate as-big chunks of memory, so it threw OutOfMemoryExceptions on smaller files. What have you gained? The unit test was supposed to test whether you can handle bigger files on a real system, right?
The important thing is presumably that you can handle files "as big as they need to be" on whatever system they're going to be running on, and there's no real way to unit test that outside of trying out that file on that system.
(A smaller, less important thing might be whether you handle
OutOfMemoryException
s gracefully, but you don't need to actually run out of memory to test that; just make your method throw an exception once in a while and observe that it does the right thing.)在进程中很容易导致内存不足异常。
只需创建一个循环,在足够小的块中分配内存,以便不在大对象堆上(但不要太多,导致异常),然后您可以尝试打开一个较小的文件,这将导致打开文件无法分配足够的连续内存,并且在不需要大文件的情况下打开文件时,您将收到 OOM 异常。 像这样...
如果您按原样运行上面的代码,您将在最后一行得到 OOM 异常。 但是,如果您首先注释掉循环,它将执行而不会出现错误。 您可能需要稍微调整循环才能使其每次打开文件失败,但您可以做到。 只需在测试中调用打开文件之前运行循环,您将耗尽大量内存,并且打开应该失败。
另外,如果 /3GB 开关适合您,您可能需要考虑设置它。 它并不总是正确的答案,并且有与之相关的缺点,但它将虚拟内存分割从 2GB/2GB 更改为 1GB/3GB,允许您的进程访问更多虚拟地址空间。 这将为您可以打开的文件大小提供更多的喘息空间。 同样,在将此作为解决方案之前,您应该先了解这样做的缺点,并确保如果它对您的情况有帮助,那么它是值得的。
此处是如何在服务器上启用它
It is pretty easy to cause out of memory exceptions in a process.
Just create a loop that allocates memory in blocks that are small enough to not be on the large object heap (but not too many that you have that cause the exception) and then you can try to open a smaller file and that will cause the opening of the file to not be able to allocate enough contiguous memory and you will get your OOM exception when opening your file without needing a huge file. Something like this...
If you run the above code as is, you will get a OOM exception on the last line. But, if you comment out the loop first it will execute with no errors. You will probably have to tweak the loop a little to get it to make your file open fail every time, but you can do it. Just run the loop before your call to open your file in your test and you will have used up a large chunk of memory and your open should fail.
Also, you might want to look into setting the /3GB switch if it is an option for you. It is not always the right answer and it has drawbacks associated with it, but it changes the virtual memory split form 2GB/2GB to 1GB/3GB allowing your process access to more virtual address space. This will give you a little more breathing room in the size of files that you can open. Again, you should read about the downsides of doing this before going after this as a solution and make sure that it is worth it if it helps your situation.
Here is how to enable it on the server