如何转储Java对象来自JVM堆旧代?

时间:2016-04-13 04:03:19

标签: java garbage-collection jvm mat

是否有任何工具可以转储旧一代的JVM堆?

换句话说,我如何判断一个物体是来自年轻一代还是老一代?

2 个答案:

答案 0 :(得分:3)

如果您运行Oracle JDK或OpenJDK,则可以使用HotSpot Serviceability Agent sa-jdi.jar执行此操作。它可以发现老一代的界限。下面是一个在OldGen边界内的对象之间收集堆直方图的示例。

也可以在Java进程中找到旧代的地址,参见the related question

import sun.jvm.hotspot.gc_implementation.parallelScavenge.ParallelScavengeHeap;
import sun.jvm.hotspot.gc_interface.CollectedHeap;
import sun.jvm.hotspot.memory.GenCollectedHeap;
import sun.jvm.hotspot.memory.MemRegion;
import sun.jvm.hotspot.oops.ObjectHistogram;
import sun.jvm.hotspot.oops.Oop;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;

public class OldGen extends Tool {

    public static void main(String[] args) {
        new OldGen().execute(args);
    }

    @Override
    public void run() {
        MemRegion oldRegion = getOldRegion(VM.getVM().getUniverse().heap());

        ObjectHistogram histogram = new ObjectHistogram() {
            @Override
            public boolean doObj(Oop obj) {
                return oldRegion.contains(obj.getHandle()) && super.doObj(obj);
            }
        };

        VM.getVM().getObjectHeap().iterate(histogram);
        histogram.print();
    }

    private MemRegion getOldRegion(CollectedHeap heap) {
        if (heap instanceof ParallelScavengeHeap) {
            return ((ParallelScavengeHeap) heap).oldGen().objectSpace().usedRegion();
        } else if (heap instanceof GenCollectedHeap) {
            return ((GenCollectedHeap) heap).getGen(1).usedRegion();
        } else {
            throw new UnsupportedOperationException(heap.kind() + " is not supported");
        }
    }
}

答案 1 :(得分:0)

一般来说,答案是否定的,没有。这是因为虽然JVM将堆组织到不同的部分,但是没有一个仅查看旧区域的转储机制。事实上,在较新的JVM上,有几种不同类型的区域,包括伊甸园,幸存者(一个和两个)和老一代,可以包括新生成的幽默物体。

您可以使用jmapjcmd执行堆转储,这些选项可以生成实时对象或所有内容。如果你真的需要知道你可能能够分析堆转储并确定它来自哪个区域,但总的来说,你真的不需要知道。如果您选择“直播”对象然后它(实际上)将在heapdump上执行GC以删除任何不被认为是活的对象。

更好的问题是尝试了解您尝试实现的目标,并确定是否有可以向您显示答案的工具(如各种PrintGC *标记),例如对象的推广频率。