简体   繁体   English

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

[英]How to dump Java objects came from JVM heap old generation?

Are there any tools to dump old generation of JVM heap? 是否有任何工具可以转储旧一代的JVM堆?

In other words, how can I tell if an object is came from young generation or old generation? 换句话说,我如何判断一个物体是来自年轻一代还是老一代?

If you run Oracle JDK or OpenJDK, you can do this with HotSpot Serviceability Agent sa-jdi.jar . 如果运行Oracle JDK或OpenJDK,则可以使用HotSpot Serviceability Agent sa-jdi.jar执行此sa-jdi.jar It can discover boundaries of old generation. 它可以发现老一代的界限。 Here is an example that collects heap histogram among objects within OldGen boundaries. 这是一个在OldGen边界内的对象之间收集堆直方图的示例。

It is also possible to find the addresses of old generation from within Java process, see the related question . 也可以从Java进程中找到旧代的地址,参见相关问题

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");
        }
    }
}

Generally speaking, the answer is no, there aren't. 一般来说,答案是否定的,没有。 That's because although the JVM organises the heap into different sections, there isn't a dumping mechanism which only looks at the old region. 这是因为虽然JVM将堆组织到不同的部分,但是没有一种仅查看旧区域的转储机制。 And in fact, on newer JVMs there are several different types of region, including eden, survivor (one and two) and old generations which can include newly generated humungous objects. 事实上,在较新的JVM上有几种不同类型的区域,包括伊甸园,幸存者(一个和两个)和老一代,其中可以包括新生成的幽默物体。

You can use jmap or jcmd to perform a heap dump, and these have an option to generate just the live objects or everything. 您可以使用jmapjcmd执行堆转储,这些选项可以生成实时对象或所有内容。 If you really needed to know it's possible that you might be able to analyze the heap dumps and determine which regions it came from at any point, but in general, you really don't need to know. 如果你真的需要知道你可能能够分析堆转储并确定它来自哪个区域,但总的来说,你真的不需要知道。 If you select 'live' objects then it will (in effect) perform a GC on the heapdump to remove any objects that aren't considered live. 如果选择“实时”对象,则它(实际上)将在heapdump上执行GC以删除任何不被视为活动的对象。

A better question is to try and understand what you're trying to achieve, and determine if there are tools (like the various PrintGC* flags) that will show you an answer, such as how often objects are promoted. 一个更好的问题是尝试理解你想要实现的目标,并确定是否有工具(如各种PrintGC *标志)可以显示答案,例如对象的提升频率。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM