当内存不足时bash错误代码137 vs 1

Che*_*her 5 c# bash mono

上下文

我在linux bash中运行以下命令:

mono --debug --debugger-agent=transport=dt_socket,address=198.178.155.198:10000 ./Stress.exe
Run Code Online (Sandbox Code Playgroud)

Stress.exe是一个C#应用程序.

怎么了

有一次,系统内存不足,这是需要的.返回错误代码.

返回错误代码(echo $?)

代码1:当我的程序因为内存不足而创建一个throw时.

代码137:当内存过载时被OS杀死.

题

为什么有时候操作系统会杀死我的应用程序?为什么结果并不总是一样的?

Sus*_*ver 5

假设:

  • Mono 正在运行基于 SGEN 的 GC
  • Linux OOM Killer 实际启用
  • 您的 Stress.exe 仅分配托管内存,即没有本机互操作,没有使用编组内存分配器,没有标记为不安全的代码等。
  • 您不断地创建对象并且从不释放这些引用。

让我们谈谈 SGEN,所以当你分配对象时,它们是在托儿所中创建的,当你在托儿所中耗尽内存时,当 GC 进行扫描并且必须在它已满时进行托儿所收集时,活动对象会移动到它的主要堆。如果主磁头已满,则需要更多的操作系统内存。您可以调整分配给单声道应用程序的初始内存量,甚至可以修复 Sgen 可以使用的内存量(最大值)。此外,超过 8000 字节的托管对象由 Sgen 的大型对象空间管理器处理,这是基于非苗圃/主要堆的内存,但它仍然是托管对象/内存。

因此,通常当单声道需要更多空间用于托管对象并为附加块执行操作系统请求并且操作系统拒绝时,您会看到 OutOfMemory 异常和 0 退出代码。你的压力测试是快乐的。

但是 OOM 正在观察那个单声道过程并将它的分数 (oom_score) 调整得越来越高。它可能会在任何时候触发该单声道进程,但我认为它在 GC 扫描时正确的可能性是当应用程序线程被 SGEN 挂起但在 SGEN 由于托管不足而实际执行操作系统内存请求之前nusery 中的内存空间。因此,您会得到 137 的退出。137 & 127 = 9,因此单进程被发送了一个 SIGKILL 信号(kill -9)并且您的压力测试不满意。

试试这个作为实验:

  • 1) 如果您完全关闭 OOM 杀手。假设这不是您要强调的实时制作框;-) 您应该 100% 的时间都会看到“System.OutOfMemoryException”。
  • 或 2) 将单声道进程的 oom_adj 设置为 -17,OOM 将不理会它。只需将您的单声道启动包装在一个 shell 脚本中以获取它的 pid 并将 -17 回显到该进程的 oom_adj。
  • 或 3) 如果您将单声道进程的 oom_adj 调整得更低(一直降低到 -16,那么您将看到单声道“更多时间”捕获它自己的托管内存中断,但它永远不会是 100% 的时间。 ...

这根本不是 Mono 和/或 Sgen/GC 相关的“问题”。任何消耗越来越多内存的进程都会被 OOM 杀死。无论是大型的 Oracle 数据库还是存在内存泄漏的应用程序/守护程序等等,它们都可能被杀死。