【问题标题】:Can the OS stop a Java process from garbage collecting?操作系统可以阻止 Java 进程进行垃圾收集吗?
【发布时间】:2013-04-18 18:40:57
【问题描述】:

我正在使用AppDynamics 监控生产系统,但我们只是让系统缓慢爬行,几乎死机。就在此事件之前,AppDynamics 会在几分钟内显示所有 GC 活动(次要和主要类似)扁平线......然后恢复活力。

即使在系统超低负载期间,我们仍然会看到我们的 JVM 执行 一些 GC 活动。我们从来没有让它完全平坦并下降到 0。

另外 - 网络 I/O 与 GC/内存平坦线在同一时间发生平坦化。

所以我问:系统级别的某些东西会导致 JVM 冻结,或者导致其垃圾收集挂起/冻结吗?这是在 CentOS 机器上。

【问题讨论】:

  • “系统运行缓慢,几乎死机” 是否存在内存泄漏?
  • 是的,我知道听起来是这样,但我们会看到可用内存量随着时间的推移而减少,但我们没有。不过绝对是个好主意。
  • 我之前看到过类似你描述的事情,因为 Statement 对象从未关闭,并且在一段时间后填满了堆。使用 VisualVM 或任何您喜欢的工具来检查使用了大部分内存的内容,看看它是否在不断增长。
  • 我们已经在非生产服务器上进行了同样的内存泄漏分析,但没有发现任何东西。我真的不认为这是内存泄漏......

标签: java garbage-collection jvm heap-memory appdynamics


【解决方案1】:

您的操作系统是否启用了交换。

我注意到,一旦 Java 填满了启用交换的操作系统上的所有内存,Java 就会出现巨大的问题——它实际上会破坏 Windows 系统,有效地锁定它们并导致重新启动。

我的理论是这样的:

  • 操作系统内存快满了。
  • 操作系统从 Java 请求内存。
  • 这会触发 Java 进入完整 GC 以尝试释放内存。
  • 完整的 GC 几乎会触及 VM 内存的每一块,甚至包括已换出的项目。
  • 系统尝试将数据交换回 VM 的内存(在已用完 ram 的系统上)
  • 这一直在滚雪球。

起初它不会对系统产生太大影响,但是如果您尝试启动需要大量内存的应用程序可能需要很长时间,并且您的系统只会不断降级。

多个大型 VM 会使情况变得更糟,我运行 3 或 4 个大型 VM,当我的 RAM 使用率超过 60-70% 时,我的系统现在开始占用。

这是推测,但它描述了我经过几天的测试后看到的行为。

效果是所有的交换似乎都“阻止”了 gc。更准确地说,操作系统花费了大部分 GC 时间进行交换,这使得它看起来在 GC 期间处于挂起状态。

修复--将 -Xmx 设置为较低的值,将其删除,直到您有足够的空间来避免交换。这总是解决我的问题,如果它不能解决你的问题,那么我对你问题的原因是错误的:)

【讨论】:

  • 操作系统如何准确地从进程请求内存?
  • 我相信操作系统可以发出内存不足的信号,但我找不到参考。我可能错了,但效果与描述的一样——如果 JAVA 应用程序占用了大部分 ram,则无论有多少交换可用,系统在用完 ram 后都会停止。我在 Linux 中看到过这种情况,但在 Windows 上更为明显。当我的 -Xmx 设置错误时,我不得不在机器达到内存限制时重新启动它。此外,GC 似乎在这段时间内停止了,因为操作系统正在花费所有时间进行交换(正如 TicketMonster 所描述的那样。)
  • 这个信号呢? msdn.microsoft.com/en-us/library/windows/desktop/… 如果 Java 对此做出响应,它将解释我所描述的行为。
【解决方案2】:

如果没有更多信息,很难找到问题的确切原因。

但我可以尝试回答您的问题:
操作系统可以阻止垃圾收集吗?
您的操作系统不太可能阻止线程垃圾收集器并让其他线程运行。你不应该那样调查。

操作系统可以阻止 JVM 吗?
是的,它 perflecty 可以而且做得很多,但是速度比您想象的要快,所有进程都在同时运行。
jvm 是一个与其他进程一样的进程,并且在操作系统的控制下。您必须检查应用程序在挂起时使用的 cpu(在不在 jvm 中的服务器上进行监控)。如果它非常低,那么我会看到 2 个原因(但还有更多):

  • 您的服务器没有足够的 RAM 并且正在交换(RAM 磁盘),进程变得非常缓慢。在这种情况下,服务器上的 cpu 会很高,但 jvm 上的 cpu 会很低
  • 另一个进程或服务器获取资源,而您的应用程序或服务器什么也没有收到。检查 CentO 的优先级。

【讨论】:

    【解决方案3】:

    理论上,是的,它可以。但它会练习,它永远不会。

    在大多数 Java 虚拟机中,应用程序线程并不是唯一运行的线程。除了应用程序线程之外,还有编译线程、终结器线程、垃圾回收线程等等。将 CPU 内核分配给这些线程和机器上运行的其他程序的其他线程的调度决策基于许多参数(线程优先级、它们的最后执行时间等),这些参数尽量对所有线程公平。因此,实际上,系统中的任何线程都不应等待 CPU 分配的时间过长,操作系统也不应无限期地阻塞任何线程。

    垃圾收集线程(和其他 VM 线程)需要做的活动很少。他们需要定期检查是否需要垃圾收集。即使应用程序线程全部挂起,也可能有其他 VM 线程(例如 JIT 编译器线程或终结器线程)在工作,因此分配对象并触发垃圾回收。对于使用 Java 而不是 C/C++ 实现 VM 线程的元循环 JVM 尤其如此;

    此外,大多数现代 JVM 使用分代垃圾收集器(一种将堆划分为单独空间并将具有不同年龄的对象放入堆的不同部分的垃圾收集器)这意味着随着对象越来越老,它们需要搬到其他较旧的空间。因此,即使不需要收集对象,分代垃圾收集器也可能将对象从一个空间移动到另一个空间。

    当然每个垃圾收集器的细节在不同的 JVM 到 JVM 中是不同的。为了在伤害上加点盐,一些 JVM 支持不止一种类型的垃圾收集器。但是在空闲应用程序中看到最小的垃圾收集活动并不奇怪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-04
      • 2022-01-11
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 2012-12-16
      • 2014-12-07
      • 2018-06-10
      相关资源
      最近更新 更多