6

问题很简单我有一个过程,对一些 xml 文件执行 ETL。我们开始得到非常大的 xml 文件,并且我开始得到 OutOfMemoryExceptions。

修复过程相对简单。但是,我想为我的 NUnit 套件进行单元测试,以确保该过程将继续能够处理非常大的文件。然而,实际上我的开发工作站内存不足会减慢我的机器速度,并且非常耗时。在版本控制中存储一个巨大的测试文件也是一个坏主意。如果我可以人为地将进程、线程或应用程序域限制为仅使用固定数量的 ram,比如说 128 兆,我可以进行更小的单元测试,不会让我的工作站屈服。

有什么建议么?我可以 P/Invoke 他们的一些非托管 API 吗?

4

4 回答 4

2

您不能使用模拟框架进行内存分配并将其OutOfMemoryException作为测试之一抛出吗?

话虽如此,如果您真的内存不足,那么您的应用程序可以安全地做很多事情,但如果您至少可以优雅地失败,您的用户将不胜感激。

一个例子: 我在以前的工作中有一个案例,我们实时显示工厂的 3D 模型。模型变得如此之大,以至于当我们尝试加载纹理时,我们会摆脱内存故障。我们设法通过确保代码处理空指针来保持应用程序的活动和渲染,即使其余代码认为那里应该有纹理信息。

于 2009-05-07T18:41:58.850 回答
1

嘲讽是最好的。实际上提出OOM是定义而不是单元测试。在处理内存时,您正在处理负载测试。如果您阅读了这封电子邮件底部的链接,您会发现真正的 OOM 在最好的情况下很难重现和调试。人为的 OOM 异常并不是异常的真正原因,因此没有比模拟测试更有趣。

坚持使用模拟进行单元测试进行验证。如果您仍然遇到 OOM,请在服务器上投入更多内存并让您的进程更频繁地回收/重新启动。

这是我上次与它们战斗时收集的关于 OutMemoryExceptions 的一些有趣的读物。摘要:当系统无法分配您请求的数量时,就会发生 OOM——这并不意味着您的内存不足。

于 2009-05-07T20:06:43.703 回答
0

在进程中很容易导致内存不足异常。

只需创建一个循环,在足够小的块中分配内存,而不是在大对象堆上(但不要太多导致异常),然后您可以尝试打开一个较小的文件,这将导致打开文件无法分配足够的连续内存,并且在不需要大文件的情况下打开文件时会出现 OOM 异常。像这样的东西...

List<byte[]> items = new List<byte[]>();
for (int i = 0; i < 10000; i++)
{
     byte[] c = new byte[160000];
     items.Add(c);
}

byte[] next = new byte[1000000000];

如果你按原样运行上面的代码,你会在最后一行得到一个OOM异常。但是,如果您先注释掉循环,它将执行没有错误。您可能需要稍微调整循环以使其每次打开文件都失败,但您可以做到。只需在调用之前运行循环以在测试中打开文件,您将耗尽大量内存并且您的打开应该失败。

此外,如果您可以选择设置 /3GB 开关,您可能需要考虑它。它并不总是正确的答案,它也有与之相关的缺点,但它会将虚拟内存拆分从 2GB/2GB 更改为 1GB/3GB,从而允许您的进程访问更多虚拟地址空间。这将为您可以打开的文件大小提供更多喘息空间。同样,在将其作为解决方案之前,您应该阅读有关这样做的缺点,并确保如果它有助于您的情况,它是值得的。

是在服务器上启用它的方法

于 2009-05-07T23:10:59.673 回答
0

我不太明白你在这里的意思。假设您以某种方式创建了一个人为的小型“测试环境”,它无法分配这么大的内存块,因此它在较小的文件上抛出了 OutOfMemoryExceptions。你有什么收获?单元测试应该测试您是否可以在真实系统上处理更大的文件,对吗?

重要的事情大概是您可以在将要运行的任何系统上处理“尽可能大”的文件,并且除了在该系统上尝试该文件之外,没有真正的方法可以对其进行单元测试。

(一个更小、更不重要的事情可能是您是否OutOfMemoryException优雅地处理 s,但您实际上不需要用完内存来测试它;只需让您的方法偶尔抛出一个异常并观察它是否正确.)

于 2009-05-07T18:30:50.330 回答