/* * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others * at JavaSoft/Sun.
*/
finalstaticint MAGIC_NUMBER = 0x4a415641; // That's "JAVA", the first part of "JAVA PROFILE ..." privatefinalstatic String[] VERSIONS = { " PROFILE 1.0\0", " PROFILE 1.0.1\0", " PROFILE 1.0.2\0",
};
privatefinalstaticint VERSION_JDK12BETA3 = 0; privatefinalstaticint VERSION_JDK12BETA4 = 1; privatefinalstaticint VERSION_JDK6 = 2; // These version numbers are indices into VERSIONS. The instance data // member version is set to one of these, and it drives decisions when // reading the file. // // Version 1.0.1 added HPROF_GC_PRIM_ARRAY_DUMP, which requires no // version-sensitive parsing. // // Version 1.0.1 changed the type of a constant pool entry from a signature // to a typecode. // // Version 1.0.2 added HPROF_HEAP_DUMP_SEGMENT and HPROF_HEAP_DUMP_END // to allow a large heap to be dumped as a sequence of heap dump segments. // // The HPROF agent in J2SE 1.2 through to 5.0 generate a version 1.0.1 // file. In Java SE 6.0 the version is either 1.0.1 or 1.0.2 depending on // the size of the heap (normally it will be 1.0.1 but for multi-GB // heaps the heap dump will not fit in a HPROF_HEAP_DUMP record so the // dump is generated as version 1.0.2).
privateint version; // The version of .hprof being read
privateint debugLevel; privatelong currPos; // Current position in the file
privateint dumpsToSkip; privateboolean callStack; // If true, read the call stack of objects
privateint identifierSize; // Size, in bytes, of identifiers. private Hashtable<Long, String> names;
// Hashtable<Integer, ThreadObject>, used to map the thread sequence number // (aka "serial number") to the thread object ID for // HPROF_GC_ROOT_THREAD_OBJ. ThreadObject is a trivial inner class, // at the end of this file. private Hashtable<Integer, ThreadObject> threadObjects;
// Hashtable<Long, String>, maps class object ID to class name // (with / converted to .) private Hashtable<Long, String> classNameFromObjectID;
// Hashtable<Integer, Integer>, maps class serial # to class object ID private Hashtable<Integer, String> classNameFromSerialNo;
// Hashtable<Long, StackFrame> maps stack frame ID to StackFrame. // Null if we're not tracking them. private Hashtable<Long, StackFrame> stackFrames;
// Hashtable<Integer, StackTrace> maps stack frame ID to StackTrace // Null if we're not tracking them. private Hashtable<Integer, StackTrace> stackTraces;
public HprofReader(ReadBuffer readBuffer, PositionDataInputStream in, int dumpNumber, boolean callStack, int debugLevel) throws IOException { super(in); this.snapshot = new Snapshot(readBuffer); this.dumpsToSkip = dumpNumber - 1; this.callStack = callStack; this.debugLevel = debugLevel;
names = new Hashtable<Long, String>();
threadObjects = new Hashtable<Integer, ThreadObject>(43);
classNameFromObjectID = new Hashtable<Long, String>(); if (callStack) {
stackFrames = new Hashtable<Long, StackFrame>(43);
stackTraces = new Hashtable<Integer, StackTrace>(43);
classNameFromSerialNo = new Hashtable<Integer, String>();
}
}
public HprofReader(String fileName, PositionDataInputStream in, int dumpNumber, boolean callStack, int debugLevel) throws IOException { this(MappedReadBuffer.create(new RandomAccessFile(fileName, "r")),
in, dumpNumber, callStack, debugLevel);
}
public Snapshot read() throws IOException {
currPos = 4; // 4 because of the magic number
version = readVersionHeader();
identifierSize = in.readInt();
snapshot.setIdentifierSize(identifierSize); if (version >= VERSION_JDK12BETA4) {
snapshot.setNewStyleArrayClass(true);
} else {
snapshot.setNewStyleArrayClass(false);
}
currPos += 4; if (identifierSize != 4 && identifierSize != 8) { thrownew IOException("I'm sorry, but I can't deal with an identifier size of " + identifierSize + ". I can only deal with 4 or 8.");
}
System.out.println("Dump file created " + (new Date(in.readLong())));
currPos += 8;
for (;;) { int type; try {
type = in.readUnsignedByte();
} catch (EOFException ignored) { break;
}
in.readInt(); // Timestamp of this record // Length of record: readInt() will return negative value for record // length >2GB. so store 32bit value in long to keep it unsigned. long length = in.readInt() & 0xffffffffL; if (debugLevel > 0) {
System.out.println("Read record type " + type
+ ", length " + length
+ " at position " + toHex(currPos));
} if (length < 0) { thrownew IOException("Bad record length of " + length
+ " at byte " + toHex(currPos+5)
+ " of file.");
}
currPos += 9 + length; switch (type) { case HPROF_UTF8: { long id = readID(); byte[] chars = newbyte[(int)length - identifierSize];
in.readFully(chars);
names.put(id, new String(chars)); break;
} case HPROF_LOAD_CLASS: { int serialNo = in.readInt(); // Not used long classID = readID(); int stackTraceSerialNo = in.readInt(); long classNameID = readID(); Long classIdI = classID;
String nm = getNameFromID(classNameID).replace('/', '.');
classNameFromObjectID.put(classIdI, nm); if (classNameFromSerialNo != null) {
classNameFromSerialNo.put(serialNo, nm);
} break;
}
case HPROF_HEAP_DUMP_END: { if (version >= VERSION_JDK6) { if (dumpsToSkip <= 0) {
skipBytes(length); // should be no-op return snapshot;
} else { // skip this dump (of the end record for a sequence of dump segments)
dumpsToSkip--;
}
} else { // HPROF_HEAP_DUMP_END only recognized in >= 1.0.2
warn("Ignoring unrecognized record type " + type);
}
skipBytes(length); // should be no-op break;
}
case HPROF_HEAP_DUMP_SEGMENT: { if (version >= VERSION_JDK6) { if (dumpsToSkip <= 0) { try { // read the dump segment
readHeapDump(length, currPos);
} catch (EOFException exp) {
handleEOF(exp, snapshot);
}
} else { // all segments comprising the heap dump will be skipped
skipBytes(length);
}
} else { // HPROF_HEAP_DUMP_SEGMENT only recognized in >= 1.0.2
warn("Ignoring unrecognized record type " + type);
skipBytes(length);
} break;
}
case HPROF_FRAME: { if (stackFrames == null) {
skipBytes(length);
} else { long id = readID();
String methodName = getNameFromID(readID());
String methodSig = getNameFromID(readID());
String sourceFile = getNameFromID(readID()); int classSer = in.readInt();
String className = classNameFromSerialNo.get(classSer); int lineNumber = in.readInt(); if (lineNumber < StackFrame.LINE_NUMBER_NATIVE) {
warn("Weird stack frame line number: " + lineNumber);
lineNumber = StackFrame.LINE_NUMBER_UNKNOWN;
}
stackFrames.put(id, new StackFrame(methodName, methodSig,
className, sourceFile,
lineNumber));
} break;
} case HPROF_TRACE: { if (stackTraces == null) {
skipBytes(length);
} else { int serialNo = in.readInt(); int threadSeq = in.readInt(); // Not used
StackFrame[] frames = new StackFrame[in.readInt()]; for (int i = 0; i < frames.length; i++) { long fid = readID();
frames[i] = stackFrames.get(fid); if (frames[i] == null) { thrownew IOException("Stack frame " + toHex(fid) + " not found");
}
}
stackTraces.put(serialNo, new StackTrace(frames));
} break;
} case HPROF_UNLOAD_CLASS: case HPROF_ALLOC_SITES: case HPROF_START_THREAD: case HPROF_END_THREAD: case HPROF_HEAP_SUMMARY: case HPROF_CPU_SAMPLES: case HPROF_CONTROL_SETTINGS: case HPROF_LOCKSTATS_WAIT_TIME: case HPROF_LOCKSTATS_HOLD_TIME:
{ // Ignore these record types
skipBytes(length); break;
} default: {
skipBytes(length);
warn("Ignoring unrecognized record type " + type);
}
}
}
// // Read a java value. If result is non-null, it's expected to be an // array of one element. We use it to fake multiple return values. // @returns the number of bytes read // privateint readValue(JavaThing[] resultArr) throws IOException { byte type = in.readByte(); return 1 + readValueForType(type, resultArr);
}
private String getNameFromID(Long id) throws IOException { if (id.longValue() == 0L) { return"";
}
String result = names.get(id); if (result == null) {
warn("Name not found at " + toHex(id.longValue())); return"unresolved name " + toHex(id.longValue());
} return result;
}
private StackTrace getStackTraceFromSerial(int ser) throws IOException { if (stackTraces == null) { returnnull;
}
StackTrace result = stackTraces.get(ser); if (result == null) {
warn("Stack trace not found for serial # " + ser);
} return result;
}
// // Handle a HPROF_GC_CLASS_DUMP // Return number of bytes read // privateint readClass() throws IOException { long id = readID();
StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); long superId = readID(); long classLoaderId = readID(); long signersId = readID(); long protDomainId = readID(); long reserved1 = readID(); long reserved2 = readID(); int instanceSize = in.readInt(); int bytesRead = 7 * identifierSize + 8;
int numConstPoolEntries = in.readUnsignedShort();
bytesRead += 2; for (int i = 0; i < numConstPoolEntries; i++) { int index = in.readUnsignedShort(); // unused
bytesRead += 2;
bytesRead += readValue(null); // We ignore the values
}
int numStatics = in.readUnsignedShort();
bytesRead += 2;
JavaThing[] valueBin = new JavaThing[1];
JavaStatic[] statics = new JavaStatic[numStatics]; for (int i = 0; i < numStatics; i++) { long nameId = readID();
bytesRead += identifierSize; byte type = in.readByte();
bytesRead++;
bytesRead += readValueForType(type, valueBin);
String fieldName = getNameFromID(nameId); if (version >= VERSION_JDK12BETA4) {
type = signatureFromTypeId(type);
}
String signature = "" + ((char) type);
JavaField f = new JavaField(fieldName, signature);
statics[i] = new JavaStatic(f, valueBin[0]);
}
int numFields = in.readUnsignedShort();
bytesRead += 2;
JavaField[] fields = new JavaField[numFields]; for (int i = 0; i < numFields; i++) { long nameId = readID();
bytesRead += identifierSize; byte type = in.readByte();
bytesRead++;
String fieldName = getNameFromID(nameId); if (version >= VERSION_JDK12BETA4) {
type = signatureFromTypeId(type);
}
String signature = "" + ((char) type);
fields[i] = new JavaField(fieldName, signature);
}
String name = classNameFromObjectID.get(id); if (name == null) {
warn("Class name not found for " + toHex(id));
name = "unknown-name@" + toHex(id);
}
JavaClass c = new JavaClass(id, name, superId, classLoaderId, signersId,
protDomainId, fields, statics,
instanceSize);
snapshot.addClass(id, c);
snapshot.setSiteTrace(c, stackTrace);
// // Handle a HPROF_GC_INSTANCE_DUMP // Return number of bytes read // privateint readInstance() throws IOException { long start = in.position(); long id = readID();
StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); long classID = readID();
JavaClass searchedClass = snapshot.findClass( "0x" + Long.toHexString(classID)); if (searchedClass == null) { thrownew IOException( "Class Record for 0x" + Long.toHexString(classID) + " not found");
} int bytesFollowing = in.readInt(); int bytesRead = (2 * identifierSize) + 8 + bytesFollowing;
JavaObject jobj = new JavaObject(classID, start);
skipBytes(bytesFollowing);
snapshot.addHeapObject(id, jobj);
snapshot.setSiteTrace(jobj, stackTrace); return bytesRead;
}
// // Handle a HPROF_GC_OBJ_ARRAY_DUMP or HPROF_GC_PRIM_ARRAY_DUMP // Return number of bytes read // privatelong readArray(boolean isPrimitive) throws IOException { long start = in.position(); long id = readID();
StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); int num = in.readInt(); long bytesRead = identifierSize + 8; long elementClassID; if (isPrimitive) {
elementClassID = in.readByte();
bytesRead++;
} else {
elementClassID = readID();
bytesRead += identifierSize;
}
// Check for primitive arrays: byte primitiveSignature = 0x00; int elSize = 0; if (isPrimitive || version < VERSION_JDK12BETA4) { switch ((int)elementClassID) { case T_BOOLEAN: {
primitiveSignature = (byte) 'Z';
elSize = 1; break;
} case T_CHAR: {
primitiveSignature = (byte) 'C';
elSize = 2; break;
} case T_FLOAT: {
primitiveSignature = (byte) 'F';
elSize = 4; break;
} case T_DOUBLE: {
primitiveSignature = (byte) 'D';
elSize = 8; break;
} case T_BYTE: {
primitiveSignature = (byte) 'B';
elSize = 1; break;
} case T_SHORT: {
primitiveSignature = (byte) 'S';
elSize = 2; break;
} case T_INT: {
primitiveSignature = (byte) 'I';
elSize = 4; break;
} case T_LONG: {
primitiveSignature = (byte) 'J';
elSize = 8; break;
}
} if (version >= VERSION_JDK12BETA4 && primitiveSignature == 0x00) { thrownew IOException("Unrecognized typecode: "
+ elementClassID);
}
} if (primitiveSignature != 0x00) { long size = elSize * (long)num;
bytesRead += size;
JavaValueArray va = new JavaValueArray(primitiveSignature, start);
skipBytes(size);
snapshot.addHeapObject(id, va);
snapshot.setSiteTrace(va, stackTrace);
} else { long sz = (long)num * identifierSize;
bytesRead += sz;
JavaObjectArray arr = new JavaObjectArray(elementClassID, start);
skipBytes(sz);
snapshot.addHeapObject(id, arr);
snapshot.setSiteTrace(arr, stackTrace);
} return bytesRead;
}
privatebyte signatureFromTypeId(byte typeId) throws IOException { switch (typeId) { case T_CLASS: { return (byte) 'L';
} case T_BOOLEAN: { return (byte) 'Z';
} case T_CHAR: { return (byte) 'C';
} case T_FLOAT: { return (byte) 'F';
} case T_DOUBLE: { return (byte) 'D';
} case T_BYTE: { return (byte) 'B';
} case T_SHORT: { return (byte) 'S';
} case T_INT: { return (byte) 'I';
} case T_LONG: { return (byte) 'J';
} default: { thrownew IOException("Invalid type id of " + typeId);
}
}
}
privatevoid handleEOF(EOFException exp, Snapshot snapshot) { if (debugLevel > 0) {
exp.printStackTrace();
}
warn("Unexpected EOF. Will miss information..."); // we have EOF, we have to tolerate missing references
snapshot.setUnresolvedObjectsOK(true);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.