Repository navigation
jcmd jmap
ceragon edited this page Jun 16, 2022
·
2 revisions
$ jhsdb jmap --heap --pid 31556
JVM version is 11.0.4+11-LTS
using thread-local object allocation.
Garbage-First (G1) GC with 13 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 1363144 (1.2999954223632812MB)
MaxNewSize = 1287651328 (1228.0MB)
OldSize = 5452592 (5.1999969482421875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 528482304 (504.0MB)
MaxMetaspaceSize = 536870912 (512.0MB)
G1HeapRegionSize = 4194304 (4.0MB)
Heap Usage:
G1 Heap:
regions = 512
capacity = 2147483648 (2048.0MB)
used = 645041952 (615.1599426269531MB)
free = 1502441696 (1432.8400573730469MB)
30.037106573581696% used
G1 Young Generation:
Eden Space:
regions = 4
capacity = 29360128 (28.0MB)
used = 16777216 (16.0MB)
free = 12582912 (12.0MB)
57.142857142857146% used
Survivor Space:
regions = 1
capacity = 4194304 (4.0MB)
used = 4194304 (4.0MB)
free = 0 (0.0MB)
100.0% used
G1 Old Generation:
regions = 150
capacity = 629145600 (600.0MB)
used = 624070432 (595.1599426269531MB)
free = 5075168 (4.840057373046875MB)
99.19332377115886% used$ ./jhsdb jmap --histo --pid 15532
JVM version is 11.0.4+11-LTS
Iterating over heap. This may take a while...
Object Histogram:
num #instances #bytes Class description
--------------------------------------------------------------------------
1: 50053 9540128 byte[]
2: 9645 3826408 char[]
3: 14071 1163648 int[]
4: 18019 915568 java.lang.Object[]
5: 19258 462192 java.lang.String
6: 3854 456280 java.lang.Class
7: 6481 311088 java.util.HashMap
8: 8605 275360 java.util.concurrent.ConcurrentHashMap$Node
9: 2975 238000 sun.rmi.transport.ConnectionInputStream
10: 5950 238000 java.io.ObjectOutputStream$HandleTable
11: 2975 214200 sun.rmi.transport.ConnectionOutputStream
12: 13243 211888 java.lang.Object
13: 6010 192320 java.rmi.server.UID
14: 5624 179968 java.util.HashMap$Node
Total : 247963 20974000
Heap traversal took 3.763 seconds.public class SALauncher {
public static void main(String[] args) {
String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
if (args[0].equals("jmap")) {
runJMAP(oldArgs);
return;
}
}
private static void runJMAP(String[] oldArgs) {
SAGetopt sg = new SAGetopt(oldArgs);
String[] longOpts = {"exe=", "core=", "pid=",
"heap", "binaryheap", "dumpfile=", "histo", "clstats", "finalizerinfo"};
ArrayList<String> newArgs = new ArrayList();
String pid = null;
while ((s = sg.next(null, longOpts)) != null) {
if (s.equals("pid")) {
pid = sg.getOptarg();
continue;
}
if (s.equals("heap")) {
newArgs.add("-heap");
continue;
}
}
buildAttachArgs(newArgs, pid, exe, core, false);
JMap.main(newArgs.toArray(new String[newArgs.size()]));
}
}public class JMap extends Tool {
public static void main(String[] args) {
int mode = MODE_PMAP;
if (args.length > 1) {
if (modeFlag.equals("-histo")) {
mode = MODE_HISTOGRAM;
}
}
JMap jmap = new JMap(mode);
jmap.execute(args);
}
}public abstract class Tool implements Runnable {
private int debugeeType;
protected void execute(String[] args) {
returnStatus = start(args);
}
private int start(String[] args) {
int pid = 0;
switch (args.length) {
case 1:
pid = Integer.parseInt(args[0]);
debugeeType = DEBUGEE_PID;
break;
}
agent = new HotSpotAgent();
switch (debugeeType) {
case DEBUGEE_PID:
out.println("Attaching to process ID " + pid + ", please wait...");
agent.attach(pid);
break;
}
out.println("Debugger attached successfully.");
startInternal();
return 0;
}
private void startInternal() {
PrintStream out = System.out;
VM vm = VM.getVM();
if (vm.isServerCompiler()) {
out.println("Server compiler detected.");
}
String version = vm.getVMRelease();
if (version != null) {
out.print("JVM version is ");
out.println(version);
}
run();
}
}public class JMap extends Tool {
public void run() {
Tool tool = null;
switch (mode) {
case MODE_HISTOGRAM:
tool = new ObjectHistogram();
break;
}
tool.setAgent(getAgent());
tool.setDebugeeType(getDebugeeType());
tool.run();
}
}public class ObjectHistogram extends Tool {
public void run() {
run(System.out, System.err);
}
public void run(PrintStream out, PrintStream err) {
ObjectHeap heap = VM.getVM().getObjectHeap();
sun.jvm.hotspot.oops.ObjectHistogram histogram = new sun.jvm.hotspot.oops.ObjectHistogram();
err.println("Iterating over heap. This may take a while...");
long startTime = System.currentTimeMillis();
heap.iterate(histogram);
long endTime = System.currentTimeMillis();
histogram.printOn(out);
float secs = (float) (endTime - startTime) / 1000.0f;
err.println("Heap traversal took " + secs + " seconds.");
}
}public class ObjectHeap {
public void iterate(HeapVisitor visitor) {
iterateLiveRegions(collectLiveRegions(), visitor, null);
}
private List collectLiveRegions() {
// 主体逻辑代码
}
private void iterateLiveRegions(List liveRegions, HeapVisitor visitor, ObjectFilter of) {
long totalSize = 0;
for (int i = 0; i < liveRegions.size(); i += 2) {
Address bottom = (Address) liveRegions.get(i);
Address top = (Address) liveRegions.get(i + 1);
totalSize += top.minus(bottom);
}
visitor.prologue(totalSize);
for (int i = 0; i < liveRegions.size(); i += 2) {
Address bottom = (Address) liveRegions.get(i);
Address top = (Address) liveRegions.get(i + 1);
OopHandle handle = bottom.addOffsetToAsOopHandle(0);
while (handle.lessThan(top)) {
Oop obj = null;
obj = newOop(handle);
if (of == null || of.canInclude(obj)) {
if (visitor.doObj(obj)) {
// doObj() returns true to abort this loop.
break;
}
}
handle = handle.addOffsetToAsOopHandle(obj.getObjectSize());
}
}
visitor.epilogue();
}
}public class ObjectHistogram implements HeapVisitor {
private HashMap map = new HashMap();
public void prologue(long size) {
}
public boolean doObj(Oop obj) {
Klass klass = obj.getKlass();
// 不存在就创建
if (!map.containsKey(klass)) map.put(klass, new ObjectHistogramElement(klass));
// 增加对象数量和总占用大小
((ObjectHistogramElement) map.get(klass)).updateWith(obj);
return false;
}
public void epilogue() {
}
}public class ObjectHistogramElement {
private Klass klass;
private long count; // Number of instances of klass
private long size; // Total size of all these instances
public ObjectHistogramElement(Klass k) {
klass = k;
count = 0;
size = 0;
}
public void updateWith(Oop obj) {
count = count + 1;
size = size + obj.getObjectSize();
}
}public class ObjectHistogram implements HeapVisitor {
public void printOn(PrintStream tty) {
List list = getElements();
ObjectHistogramElement.titleOn(tty);
Iterator iterator = list.listIterator();
int num = 0;
int totalCount = 0;
int totalSize = 0;
while (iterator.hasNext()) {
ObjectHistogramElement el = (ObjectHistogramElement) iterator.next();
num++;
totalCount += el.getCount();
totalSize += el.getSize();
tty.print(num + ":" + "\t\t");
el.printOn(tty);
}
tty.println("Total : " + "\t" + totalCount + "\t" + totalSize);
}
public List getElements() {
List list = new ArrayList();
list.addAll(map.values());
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
return ((ObjectHistogramElement) o1).compare((ObjectHistogramElement) o2);
}
});
return list;
}
}public class ObjectHistogramElement {
public static void titleOn(PrintStream tty) {
tty.println("Object Histogram:");
tty.println();
tty.println("num " + "\t" + " #instances" + "\t" + "#bytes" + "\t" + "Class description");
tty.println("--------------------------------------------------------------------------");
}
public void printOn(PrintStream tty) {
tty.print(count + "\t" + size + "\t");
tty.print(getDescription());
tty.println();
}
}结构体
public class Oop {
private OopHandle handle;
// 获取 vm 中类的信息
public Klass getKlass() {
if (VM.getVM().isCompressedKlassPointersEnabled()) {
return (Klass) compressedKlass.getValue(getHandle());
} else {
return (Klass) klass.getValue(getHandle());
}
}
// 计算对象大小
public long getObjectSize() {
Klass k = getKlass();
return ((InstanceKlass) k).getObjectSize(this);
}
}public class ObjectHeap {
private List collectLiveRegions() {
List liveRegions = new ArrayList();
LiveRegionsCollector lrc = new LiveRegionsCollector(liveRegions);
CollectedHeap heap = VM.getVM().getUniverse().heap();
if (heap instanceof G1CollectedHeap) {
G1CollectedHeap g1h = (G1CollectedHeap) heap;
g1h.heapRegionIterate(lrc);
}
if (VM.getVM().getUseTLAB()) {
for (JavaThread thread = VM.getVM().getThreads().first(); thread != null;
thread = thread.next()) {
ThreadLocalAllocBuffer tlab = thread.tlab();
if (tlab.start() != null) {
liveRegions.add(tlab.start());
liveRegions.add(tlab.start());
liveRegions.add(tlab.top());
liveRegions.add(tlab.hardEnd());
}
}
}
sortLiveRegions(liveRegions);
return liveRegions;
}
}public class Universe {
private static AddressField collectedHeapField;
private static VirtualConstructor heapConstructor;
private static synchronized void initialize(TypeDataBase db) {
collectedHeapField = type.getAddressField("_collectedHeap");
heapConstructor = new VirtualConstructor(db);
addHeapTypeIfInDB(db, G1CollectedHeap.class);
}
public CollectedHeap heap() {
return (CollectedHeap) heapConstructor.instantiateWrapperFor(collectedHeapField.getValue());
}
}public class VirtualConstructor extends InstanceConstructor<VMObject> {
private TypeDataBase db;
private Map map;
public VMObject instantiateWrapperFor(Address addr) throws WrongTypeException {
for (Iterator iter = map.keySet().iterator(); iter.hasNext(); ) {
String typeName = (String) iter.next();
if (db.addressTypeIsEqualToType(addr, db.lookupType(typeName))) {
return (VMObject) VMObjectFactory.newObject((Class) map.get(typeName), addr);
}
}
}
}public class G1CollectedHeap extends CollectedHeap {
public G1CollectedHeap(Address addr) {
super(addr);
}
}public class G1CollectedHeap extends CollectedHeap {
// HeapRegionManager _hrm;
static private long hrmFieldOffset;
protected Address addr;
public void heapRegionIterate(SpaceClosure scl) {
Iterator<HeapRegion> iter = heapRegionIterator();
while (iter.hasNext()) {
HeapRegion hr = iter.next();
scl.doSpace(hr);
}
}
private Iterator<HeapRegion> heapRegionIterator() {
return hrm().heapRegionIterator();
}
public HeapRegionManager hrm() {
Address hrmAddr = addr.addOffsetTo(hrmFieldOffset);
return (HeapRegionManager) VMObjectFactory.newObject(HeapRegionManager.class,
hrmAddr);
}
}public class HeapRegionManager extends VMObject {
protected Address addr;
// G1HeapRegionTable _regions
static private long regionsFieldOffset;
public HeapRegionManager(Address addr) {
super(addr);
}
public Iterator<HeapRegion> heapRegionIterator() {
return regions().heapRegionIterator(length());
}
private G1HeapRegionTable regions() {
Address regionsAddr = addr.addOffsetTo(regionsFieldOffset);
return (G1HeapRegionTable) VMObjectFactory.newObject(G1HeapRegionTable.class, regionsAddr);
}
public long length() {
return regions().length();
}
}public class G1HeapRegionTable extends VMObject {
// HeapRegion** _base;
static private AddressField baseField;
// uint _length;
static private CIntegerField lengthField;
public G1HeapRegionTable(Address addr) {
super(addr);
}
public Iterator<HeapRegion> heapRegionIterator(long committedLength) {
return new HeapRegionIterator(committedLength);
}
public long length() {
return lengthField.getValue(addr);
}
private class HeapRegionIterator implements Iterator<HeapRegion> {
private long index;
private long length;
private HeapRegion next;
HeapRegionIterator(long totalLength) {
index = 0;
length = totalLength;
positionToNext();
}
public HeapRegion positionToNext() {
HeapRegion result = next;
while (index < length && at(index) == null) {
index++;
}
if (index < length) {
next = at(index);
index++; // restart search at next element
} else {
next = null;
}
return result;
}
@Override
public HeapRegion next() {
return positionToNext();
}
}
private HeapRegion at(long index) {
Address arrayAddr = baseField.getValue(addr);
// Offset of &_base[index]
long offset = index * VM.getVM().getAddressSize();
Address regionAddr = arrayAddr.getAddressAt(offset);
return (HeapRegion) VMObjectFactory.newObject(HeapRegion.class,
regionAddr);
}
}public class HeapRegion extends CompactibleSpace {
private static AddressField bottomField;
static private AddressField topField;
private static long typeFieldOffset;
private HeapRegionType type;
public HeapRegion(Address addr) {
super(addr);
Address typeAddr = (addr instanceof OopHandle) ? addr.addOffsetToAsOopHandle(typeFieldOffset)
: addr.addOffsetTo(typeFieldOffset);
type = (HeapRegionType) VMObjectFactory.newObject(HeapRegionType.class, typeAddr);
}
@Override
public List getLiveRegions() {
List res = new ArrayList();
res.add(new MemRegion(bottom(), top()));
return res;
}
public Address bottom() {
return bottomField.getValue(addr);
}
public Address top() {
return topField.getValue(addr);
}
}public class ObjectHeap {
public Oop newOop(OopHandle handle) {
Klass klass = Oop.getKlassForOopHandle(handle);
if (klass != null) {
if (klass instanceof TypeArrayKlass) return new TypeArray(handle, this);
if (klass instanceof ObjArrayKlass) return new ObjArray(handle, this);
if (klass instanceof InstanceKlass) return new Instance(handle, this);
}
}
}public class Oop {
private static CIntField mark;
private static MetadataField klass;
private static NarrowKlassField compressedKlass;
public static Klass getKlassForOopHandle(OopHandle handle) {
if (VM.getVM().isCompressedKlassPointersEnabled()) {
return (Klass)Metadata.instantiateWrapperFor(handle.getCompKlassAddressAt(compressedKlass.getOffset()));
} else {
return (Klass)Metadata.instantiateWrapperFor(handle.getAddressAt(klass.getOffset()));
}
}
}abstract public class Metadata extends VMObject {
private static VirtualBaseConstructor<Metadata> metadataConstructor;
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
metadataConstructor.addMapping("Klass", Klass.class);
}
public static Metadata instantiateWrapperFor(Address addr) {
return metadataConstructor.instantiateWrapperFor(addr);
}
}public class Klass extends Metadata implements ClassConstants {
public Klass(Address addr) {
super(addr);
}
}