简体   繁体   English

仅在发布时编译时抛出OutOfMemoryException

[英]OutOfMemoryException thrown only when compiling in release

I have a C# Console application that allocates lots of small objects and arrays. 我有一个C#Console应用程序,它分配了许多小对象和数组。 These objects have a short life time and quickly get cleaned up by the garbage collector. 这些物体的使用寿命很短,很快就会被垃圾收集器清理干净。 To the question "why do you need to allocate so much short life objects, you should avoid this" : the program is used for a heavy AI task and there is no obvious way to get around this for now. 对于“你为什么需要分配如此多的短生命对象,你应该避免这种情况”的问题 :该程序用于繁重的AI任务,现在没有明显的方法来解决这个问题。

Here is the problem: 这是问题所在:

If I run the program in debug mode x86 it runs fine and finishes processing everything after a few minutes. 如果我在调试模式x86下运行程序它运行正常并在几分钟后完成所有处理。 In average, it uses 300-400 MB. 平均而言,它使用300-400 MB。

If I take that exact same program, but compile and run it in release x86 mode, the memory used by the program quickly reaches 2GB (in a few seconds) so it throws an OutOfMemoryException (which is expected behavior since it's a 32 bit application). 如果我采用完全相同的程序,但在发布x86模式下编译并运行它,程序使用的内存很快就会达到2GB(几秒钟内),因此它会抛出一个OutOfMemoryException (这是预期的行为,因为它是一个32位的应用程序) 。 Compiling it in release x64 mode does not solve the problem at all, it quickly uses all memory of the computer (8GB), then crashes when a memory allocation fails. 在发布x64模式下进行编译并不能解决问题,它会快速使用计算机的所有内存(8GB),然后在内存分配失败时崩溃。

I use SharpDevelop 4.3.3 to build the application. 我使用SharpDevelop 4.3.3来构建应用程序。 The only differences between debug and release mode are: 调试和发布模式之间的唯一区别是:

  • Optimize code (release only) 优化代码(仅限发布)
  • Check for arithmetic overflow/underflow (debug only) 检查算术溢出/下溢(仅限调试)
  • Debug info : full debug information (debug) / no debug information (release) 调试信息:完整的调试信息(调试)/无调试信息(发布)

In all cases no debugger is attached. 在所有情况下都没有附加调试器。 Program is pretty short and has no compiler directives that would make it run differently when compiled in debug or release. 程序非常简短,并且没有编译器指令可以使它在调试或发布时编译时运行方式不同。 There is no obvious reason to explain the behaviour. 没有明显的理由来解释这种行为。 When compiling in release mode it looks like garbage collector is never fired (or at least not enough times) and memory is not released. 在发布模式下进行编译时,看起来垃圾收集器从未被触发(或者至少没有足够的时间)并且内存未被释放。

It seems a similar question has been asked already but it does not seem to be the same issue as mine. 似乎已经提出类似的问题,但它似乎与我的问题不同。

If finally found out the reason. 如果终于找到了原因。 My fault. 我的错。

I had a one Debug.Assert() method call which not only perform some checking but also did some operation (eg : Debug.Assert(List.Remove()) ). 我有一个Debug.Assert()方法调用,它不仅执行一些检查,还做了一些操作(例如: Debug.Assert(List.Remove()) )。

I assume Debug.Assert() to be executed in both cases (release and debug) and result value to be tested only when in debug mode, but this is wrong. 我假设在两种情况下都会执行Debug.Assert() (发布和调试),并且只有在调试模式下才会测试结果值,但这是错误的。 When compiling in release mode, Debug.Assert() calls are totally removed from code. 在发布模式下编译时, Debug.Assert()调用将从代码中完全删除。

I put the answer and do not close the question, as it could be useful for someone else. 我给出了答案而不是关闭这个问题,因为它可能对其他人有用。

You could sprinkle calls within your code to force the garbage collector to run. 您可以在代码中进行调用以强制垃圾收集器运行。 For example: 例如:

    GC.Collect();
    GC.WaitForPendingFinalizers();

However, I suspect that the garbage collector is actually running, so this will not have a significant effect. 但是,我怀疑垃圾收集器实际上正在运行,所以这不会产生重大影响。 The best practice advice is to NOT try to out-think the garbage collector. 最佳实践建议是不要试图超越垃圾收集器。 I suggest this only to prove that the problem is not there. 我建议这只是为了证明问题不存在。

Usually when a program consumes all available memory, something is holding onto references to the objects such that the GC cannot free them. 通常当程序占用所有可用内存时,某些东西会持有对象的引用,这样GC就无法释放它们。

Faced with this problem I would use some sort of memory profiler to figure out what isn't being freed, and what is holding onto it. 面对这个问题,我会使用某种内存分析器来弄清楚什么没有被释放,以及什么是持有它。 There are a variety of .NET memory analysis tools out there that you can use. 您可以使用各种.NET内存分析工具。 (I'm not sure how good they are on release code). (我不确定它们在发布代码上有多好)。 I would probably try using a free trial of JetBrains dotMemory. 我可能会尝试使用JetBrains dotMemory的免费试用版。 I have not personally used it, but I have found other analysis tools from them helpful. 我没有亲自使用它,但我发现其他分析工具很有帮助。

By the way, don't apologize for using a design pattern that relies on many short-lived objects. 顺便说一句,不要为使用依赖于许多短期对象的设计模式而道歉。 It is a perfectly acceptable design pattern. 这是一种完全可以接受的设计模式。 There are some programming languages for which that is the only way to write code. 有一些编程语言是编写代码的唯一方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM