是否有工具可以转储旧的JVM堆?
换句话说,我如何知道一个对象是来自年轻代还是老年代?
是否有工具可以转储旧的JVM堆?
换句话说,我如何知道一个对象是来自年轻代还是老年代?
sa-jdi.jar
来执行此操作。它可以发现旧一代的边界。以下是一个示例,收集OldGen边界内对象的堆直方图。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");
}
}
}
更新
一款适用于JDK 11/17和G1GC的类似工具:
// Add the following JVM options to run
// --add-modules jdk.hotspot.agent
// --add-exports jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED
// --add-exports jdk.hotspot.agent/sun.jvm.hotspot.gc.g1=ALL-UNNAMED
// --add-exports jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
// --add-exports jdk.hotspot.agent/sun.jvm.hotspot.runtime=ALL-UNNAMED
// --add-exports jdk.hotspot.agent/sun.jvm.hotspot.tools=ALL-UNNAMED
// --add-exports jdk.hotspot.agent/sun.jvm.hotspot.types=ALL-UNNAMED
// --add-exports jdk.hotspot.agent/sun.jvm.hotspot.memory=ALL-UNNAMED
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.debugger.AddressException;
import sun.jvm.hotspot.debugger.OopHandle;
import sun.jvm.hotspot.gc.g1.G1CollectedHeap;
import sun.jvm.hotspot.gc.g1.HeapRegion;
import sun.jvm.hotspot.oops.Klass;
import sun.jvm.hotspot.oops.ObjectHeap;
import sun.jvm.hotspot.oops.Oop;
import sun.jvm.hotspot.oops.UnknownOopException;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;
import sun.jvm.hotspot.types.WrongTypeException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
public class OldGenHistogram extends Tool {
final Map<Klass, AtomicLong> histogram = new HashMap<>();
@Override
public void run() {
G1CollectedHeap g1Heap = (G1CollectedHeap) VM.getVM().getUniverse().heap();
for (Iterator<HeapRegion> it = g1Heap.hrm().heapRegionIterator(); it.hasNext(); ) {
HeapRegion hr = it.next();
if (hr.isOld()) {
iterate(hr);
}
}
histogram.entrySet().stream()
.sorted((e1, e2) -> Long.compare(e2.getValue().longValue(), e1.getValue().longValue()))
.forEach(e -> {
System.out.print(e.getValue() + " ");
e.getKey().printValueOn(System.out);
System.out.println();
});
}
private void iterate(HeapRegion region) {
ObjectHeap heap = VM.getVM().getObjectHeap();
Address bottom = region.bottom();
Address top = region.top();
try {
OopHandle handle = bottom.addOffsetToAsOopHandle(0);
while (handle.lessThan(top)) {
Oop obj = heap.newOop(handle);
long size = obj.getObjectSize();
histogram.computeIfAbsent(obj.getKlass(), k -> new AtomicLong())
.addAndGet(size);
handle = handle.addOffsetToAsOopHandle(size);
}
} catch (AddressException | UnknownOopException | WrongTypeException e) {
// skip
}
}
public static void main(String[] args) {
new OldGenHistogram().execute(args);
}
}