【问题标题】:Java Runnable Out of MemoryJava Runnable 内存不足
【发布时间】:2018-02-01 20:29:20
【问题描述】:

除了坏习惯...

我们实现了一个 Java 线程 Runnable 并在其 run() 中有一个 while(true) 做一些事情。 while 中的第一件事是 try/catch/finally 说,如果有任何东西被捕获,就睡觉,然后“退出”(这会一直持续下去)。

如果在更高级别的线程之外存在OutOfMemory 问题,线程会完全死掉吗?如果是这样,try/catch/finally 不会 catch 因为 OOM 的执行超出了该范围?

线程是否会被垃圾收集(它不优雅地死了)。

TLDR:如果Runnable 得到OutOfMemory,它会死掉并停止在其轨道上,还是在执行范围内抛出异常?

run(){
  while(true){
    try {
      stuff
    } catch{  //blah
    } finally{sleep}
  }
}

【问题讨论】:

  • 您是在谈论OutOfMemory 抛出在try 块内还是来自不同的线程?
  • @tsolakp 看起来像是在休眠线程中被抛出。 WARN org.hibernate.engine.loading.internal.CollectionLoadContext:389 - HHH000160: On CollectionLoadContext#cleanup, localLoadingCollectionKeys contained [10] entries Exception in thread "http-bio-8080-exec-25" java.lang.OutOfMemoryError: GC overhead limit exceeded。不久之后,我意识到while 没有启动。

标签: java garbage-collection runnable


【解决方案1】:

分配失败时抛出OutOfMemoryError。因此,它会向上传递进行分配尝试的线程的调用链。只有 try … catch 块封装此调用链,分别。分配本身可能会捕获它。

对 JVM 的整体操作和其他线程没有直接影响。当然,如果抛出OutOfMemoryError的原因是JVM内存不足,那么这种异常情况本身就有可能同时影响整个JVM操作或其他线程。例如,当时尝试分配的所有线程可能会失败并出现错误。

正如this answer 所证明的那样,如果内存太低以至于无法构造单个错误实例,则多个线程可能会遇到相同的OutOfMemoryError 实例。但这并不意味着抛出的错误可能会转移到不同的线程。在线程中分配失败和在该线程中捕获的错误之间仍然存在因果关系。或者,如果异步操作失败,并发框架可能会将错误实例移交给启动线程。

JVM 在OutOfMemoryError 上自动退出的唯一原因是间接原因;如果所有非守护线程响应 OutOfMemoryError 退出,例如当根本没有捕获它时,JVM 将退出,因为这是没有非守护线程处于活动状态时的标准行为。

在某些情况下,当 JVM 通常内存不低时,应用程序可以从单个失败的分配中恢复,例如如果失败的分配非常大(表达式new long[Integer.MAX_VALUE-8] 需要〜16GiB),如果它达到一般限制(HotSpot 不支持new long[Integer.MAX_VALUE],即使有足够的内存),或者需要特殊内存而不是普通堆空间(旧 JVM 中的本机缓冲区、图形内存或 PermGen 空间)。

【讨论】:

    【解决方案2】:

    Error 不是 Exception 出现在整个 JVM 中时 -> 在大多数情况下所有线程都会死掉。
    如果您的后台线程不使用共享资源,它可能会存活,但正如所说的那样,它非常罕见。 啊,如果它是一个恶魔线程,它将立即死亡。
    try catch 决赛是什么意思? 你无法真正捕捉到错误,它就像一颗子弹:

    一个错误是可以捕捉的,你可以尝试捕捉,但如果它抛出你就会死。

    【讨论】:

      【解决方案3】:

      又是作业时间?

      OutOfMemoryError 是错误,而不是异常。你可以捕捉到Error——毕竟它们源自ThrowableException 也是如此——但这不是一个好主意。

      你的线程不会死,你的整个 JVM 都会死。因为真的没有优雅的方法可以从OutOfMemoryError 中恢复。

      【讨论】:

      • JVM 没有必要死在OutOfMemoryError
      • 不是功课时间...调试生产时间... 颤抖,因此“抛开不良做法”。更多的是为了我的好奇心。
      • 这也不是生产代码。你写的是永远不会编译的伪Java。
      • 因为我将在制作示例时混淆 prod 代码,并保持问题的相关信息简单。
      • 作为一个有趣的反点,Akka 故意捕获 Throwables,包括内存不足,以实现优雅的关闭。在大多数情况下,这是可能的。
      【解决方案4】:

      当您在 while 循环中捕获 OutOfMemoryError 时,您分配的所有内容(假设它们仅在您的循环中被引用)直到点内存错误,都将有资格进行垃圾回收。(这也将是没有错误的情况)

      如果一个线程因为OutOfMemoryError 而死,它的堆栈将被销毁,并且仅从该堆栈引用的所有对象也将有资格进行垃圾回收。

      即使主线程因为OutOfMemoryError 而死,如果你有非守护线程活着,jvm 也不会死。

      OutOfMemoryError 可能有不同的原因,这里列出了https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks002.html

      一般建议抓到OutOfMemoryError后清理退出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-23
        • 2012-06-21
        • 2013-09-10
        • 2012-12-12
        • 2017-07-19
        • 1970-01-01
        • 2014-08-02
        • 2010-12-21
        相关资源
        最近更新 更多