【问题标题】:List instances being garbage collected列出正在被垃圾收集的实例
【发布时间】:2016-02-04 23:55:57
【问题描述】:

有没有办法查看哪些实例正在被垃圾回收?

我尝试了-XX:+PrintGC-XX:+PrintGCDetails,但这仅显示正在释放的内存量。

编辑:在这种特殊情况下,问题是我的 java 进程大小正在增加,并且我使用了很多线程,据我所知,所有线程不在堆大小上,而是在线程堆栈中,我不知道如何检查它的状态。

【问题讨论】:

  • 哪些或哪些实例
  • 将其更正为实例。
  • 你想要的是一个内存分析器。
  • @the8472 我目前正在使用 JProfiler,但我仍在寻找一种通过线程堆栈内存“浏览”的方法。我还在原始问题中添加了更多细节。

标签: java memory garbage-collection jvm


【解决方案1】:

据我了解,用于所有线程的内存不在堆大小上,而是在线程堆栈中,我不知道如何检查它的状态。

线程堆栈通常不是很大。但是一个线程可能会持有堆上的对象。这意味着堆栈上的变量是 GC 根。

Yourkit 分析器有一个GC root view。其他分析器至少应该向您显示任何活动对象到 GC 根的最短路径。

或者,您可以简单地附加一个调试器,暂停整个 VM,并使用调试器堆栈和堆遍历功能来检查当前由局部变量保存的内容。

【讨论】:

  • “线程堆栈通常不是很大。”这也是我强硬的地方。但是现在发生的是这样的:堆大小:2Gb,Permgen:400Mb,任务管理器中的大小:8.5Gb。这就是为什么我认为其他 6GB 必须在所有线程的堆栈中
  • “任务管理器中的大小”似乎是您最初的问题,看起来您正在遭受XY problem 的困扰,因为您只是假设它是线程。您可能应该查看更一般的 SO 问题,如何确定实际消耗内存的内容,或者如果找不到任何内容,请提出新问题。
  • 我没有假设 XY 问题,因为我已经分析了我的应用程序并且在 GC 运行后没有发现任何东西保存在堆中。这就是为什么我试图找到一种方法来查看线程发生了什么,因为它们保存在 JVM 的不同部分。
【解决方案2】:

如果您想监控特定类的实例,可以让它们覆盖finalize() 方法,该方法在实例被垃圾回收时调用:

@Override
protected void finalize() throws Throwable {
    super.finalize();
    // log whatever here
}

这里有一些测试代码展示了它的实际效果:

public class MyClass {

    public static void main(String[] args) throws Exception {
        new MyClass();
        System.gc();
        Thread.sleep(1000);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("Goodbye, cruel world!");
    }
}

输出:

Goodbye, cruel world!

【讨论】:

  • finalize 不保证对象已经或将永远被垃圾回收,而是应该使用幻像引用 - 请阅读 this article for further information。但是请注意,只有当幻像引用也被垃圾回收或包含引用的引用队列被清除时,目标对象才会被垃圾回收
  • @RomanVottner 没有人建议 finalize 保证任何事情。但是,finalize 保证在/如果对象被 GC 时被调用
【解决方案3】:

不,您不会通过日志记录从 JVM 中获取实例级(类不是 GC-d)信息,没有这样的设置。

要想深入了解 GC 对特定类的实例的执行情况,唯一的好选择是获取 memory dumps 并进行比较。这样您就可以从一个特定类保留。 (例如,您不小心保留了对一组流对象的引用)

更新:

既然您提到您有很多线程,请提供更多信息。线程堆栈只包含本地原语,不包含对象引用。因此,您很可能在堆转储中找到溢出的对象。如果你真的认为你的问题是由你的线程数量引起的,那么你需要使用-Xss 选项开始配置允许的堆栈大小。由于即使线程不使用此内存也会保留,因此您可能会因为生成太多线程而耗尽内存。

【讨论】:

  • 问题是我的 java 进程大小正在增加,并且我正在使用 lot 线程,据我所知,用于所有线程的内存是'不是在堆大小上,而是在线程堆栈中,我不知道如何检查它的状态。
  • @balizeiro 显而易见的解决方案是:不要使用大量线程。它们只会减慢应用程序的速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多