/* * Copyright (c) 1997, 2017, 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.
*/
/** * Represents a snapshot of the Java objects in the VM at one instant. * This is the top-level "model" object read out of a single .hprof or .bod * file.
*/
publicclass Snapshot implements AutoCloseable {
publicstaticfinallong SMALL_ID_MASK = 0x0FFFFFFFFL; publicstaticfinal JavaThing[] EMPTY_JAVATHING_ARRAY = new JavaThing[0];
privatestaticfinal JavaField[] EMPTY_FIELD_ARRAY = new JavaField[0]; privatestaticfinal JavaStatic[] EMPTY_STATIC_ARRAY = new JavaStatic[0];
// all heap objects private Hashtable<Number, JavaHeapObject> heapObjects = new Hashtable<Number, JavaHeapObject>();
private Hashtable<Number, JavaClass> fakeClasses = new Hashtable<Number, JavaClass>();
// all Roots in this Snapshot private Vector<Root> roots = new Vector<Root>();
// java.lang.ref.Reference class private JavaClass weakReferenceClass; // index of 'referent' field in java.lang.ref.Reference class privateint referentFieldIndex;
// java.lang.Class class private JavaClass javaLangClass; // java.lang.String class private JavaClass javaLangString; // java.lang.ClassLoader class private JavaClass javaLangClassLoader;
// unknown "other" array class privatevolatile JavaClass otherArrayType; // Stuff to exclude from reachable query private ReachableExcludes reachableExcludes; // the underlying heap dump buffer private ReadBuffer readBuf;
// True iff some heap objects have isNew set privateboolean hasNewSet; privateboolean unresolvedObjectsOK;
// whether object array instances have new style class or // old style (element) class. privateboolean newStyleArrayClass;
// object id size in the heap dump privateint identifierSize = 4;
// minimum object size - accounts for object header in // most Java virtual machines - we assume 2 identifierSize // (which is true for Sun's hotspot JVM). privateint minimumObjectSize;
public Snapshot(ReadBuffer buf) {
nullThing = new HackJavaValue("", 0);
readBuf = buf;
}
publicvoid addClass(long id, JavaClass c) {
addHeapObject(id, c);
putInClassesMap(c);
}
JavaClass addFakeInstanceClass(long classID, int instSize) { // Create a fake class name based on ID.
String name = "unknown-class<@" + Misc.toHex(classID) + ">";
// Create fake fields convering the given instance size. // Create as many as int type fields and for the left over // size create byte type fields. int numInts = instSize / 4; int numBytes = instSize % 4;
JavaField[] fields = new JavaField[numInts + numBytes]; int i; for (i = 0; i < numInts; i++) {
fields[i] = new JavaField("unknown-field-" + i, "I");
} for (i = 0; i < numBytes; i++) {
fields[i + numInts] = new JavaField("unknown-field-" +
i + numInts, "B");
}
// Create fake instance class
JavaClass c = new JavaClass(name, 0, 0, 0, 0, fields,
EMPTY_STATIC_ARRAY, instSize); // Add the class
addFakeClass(makeId(classID), c); return c;
}
/** * @return true iff it's possible that some JavaThing instances might * isNew set * * @see JavaThing.isNew()
*/ publicboolean getHasNewSet() { return hasNewSet;
}
// // Used in the body of resolve() // privatestaticclass MyVisitor extends AbstractJavaHeapObjectVisitor {
JavaHeapObject t; publicvoid visit(JavaHeapObject other) {
other.addReferenceFrom(t);
}
}
// To show heap parsing progress, we print a '.' after this limit privatestaticfinalint DOT_LIMIT = 5000;
/** * Called after reading complete, to initialize the structure
*/ publicvoid resolve(boolean calculateRefs) {
System.out.println("Resolving " + heapObjects.size() + " objects...");
// First, resolve the classes. All classes must be resolved before // we try any objects, because the objects use classes in their // resolution.
javaLangClass = findClass("java.lang.Class"); if (javaLangClass == null) {
System.out.println("WARNING: hprof file does not include java.lang.Class!");
javaLangClass = new JavaClass("java.lang.Class", 0, 0, 0, 0,
EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
addFakeClass(javaLangClass);
}
javaLangString = findClass("java.lang.String"); if (javaLangString == null) {
System.out.println("WARNING: hprof file does not include java.lang.String!");
javaLangString = new JavaClass("java.lang.String", 0, 0, 0, 0,
EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
addFakeClass(javaLangString);
}
javaLangClassLoader = findClass("java.lang.ClassLoader"); if (javaLangClassLoader == null) {
System.out.println("WARNING: hprof file does not include java.lang.ClassLoader!");
javaLangClassLoader = new JavaClass("java.lang.ClassLoader", 0, 0, 0, 0,
EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
addFakeClass(javaLangClassLoader);
}
for (JavaHeapObject t : heapObjects.values()) { if (t instanceof JavaClass) {
t.resolve(this);
}
}
// Now, resolve everything else. for (JavaHeapObject t : heapObjects.values()) { if (!(t instanceof JavaClass)) {
t.resolve(this);
}
}
public JavaHeapObject findThing(String id) { return findThing(Misc.parseHex(id));
}
public JavaClass findClass(String name) { if (name.startsWith("0x")) { return (JavaClass) findThing(name);
} else { return classes.get(name);
}
}
/** * Return an Iterator of all of the classes in this snapshot.
**/ public Iterator<JavaClass> getClasses() { // note that because classes is a TreeMap // classes are already sorted by name return classes.values().iterator();
}
public JavaClass[] getClassesArray() {
JavaClass[] res = new JavaClass[classes.size()];
classes.values().toArray(res); return res;
}
JavaClass clazz = findClass("java.lang.ref.Finalizer");
JavaObject queue = (JavaObject) clazz.getStaticField("queue");
JavaThing tmp = queue.getField("head");
Vector<JavaHeapObject> finalizables = new Vector<JavaHeapObject>(); if (tmp != getNullThing()) {
JavaObject head = (JavaObject) tmp; while (true) {
JavaHeapObject referent = (JavaHeapObject) head.getField("referent");
JavaThing next = head.getField("next"); if (next == getNullThing() || next.equals(head)) { break;
}
head = (JavaObject) next;
finalizables.add(referent);
}
}
finalizablesCache = new SoftReference<Vector<?>>(finalizables); return finalizables.elements();
}
public Enumeration<Root> getRoots() { return roots.elements();
}
public Root[] getRootsArray() {
Root[] res = new Root[roots.size()];
roots.toArray(res); return res;
}
public Root getRootAt(int i) { return roots.elementAt(i);
}
public ReferenceChain[]
rootsetReferencesTo(JavaHeapObject target, boolean includeWeak) {
Vector<ReferenceChain> fifo = new Vector<ReferenceChain>(); // This is slow... A real fifo would help // Must be a fifo to go breadth-first
Hashtable<JavaHeapObject, JavaHeapObject> visited = new Hashtable<JavaHeapObject, JavaHeapObject>(); // Objects are added here right after being added to fifo.
Vector<ReferenceChain> result = new Vector<ReferenceChain>();
visited.put(target, target);
fifo.addElement(new ReferenceChain(target, null));
while (fifo.size() > 0) {
ReferenceChain chain = fifo.elementAt(0);
fifo.removeElementAt(0);
JavaHeapObject curr = chain.getObj(); if (curr.getRoot() != null) {
result.addElement(chain); // Even though curr is in the rootset, we want to explore its // referers, because they might be more interesting.
}
Enumeration<JavaThing> referers = curr.getReferers(); while (referers.hasMoreElements()) {
JavaHeapObject t = (JavaHeapObject) referers.nextElement(); if (t != null && !visited.containsKey(t)) { if (includeWeak || !t.refersOnlyWeaklyTo(this, curr)) {
visited.put(t, t);
fifo.addElement(new ReferenceChain(t, chain));
}
}
}
}
ReferenceChain[] realResult = new ReferenceChain[result.size()]; for (int i = 0; i < result.size(); i++) {
realResult[i] = result.elementAt(i);
} return realResult;
}
JavaClass getArrayClass(String elementSignature) {
JavaClass clazz; synchronized(classes) {
clazz = findClass("[" + elementSignature); if (clazz == null) {
clazz = new JavaClass("[" + elementSignature, 0, 0, 0, 0,
EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
addFakeClass(clazz); // This is needed because the JDK only creates Class structures // for array element types, not the arrays themselves. For // analysis, though, we need to pretend that there's a // JavaClass for the array type, too.
}
} return clazz;
}
// Internals only below this point private Number makeId(long id) { if (identifierSize == 4) { return (int)id;
} else { return id;
}
}
privatevoid putInClassesMap(JavaClass c) {
String name = c.getName(); if (classes.containsKey(name)) { // more than one class can have the same name // if so, create a unique name by appending // - and id string to it.
name += "-" + c.getIdString();
}
classes.put(c.getName(), c);
}
privatevoid addFakeClass(JavaClass c) {
putInClassesMap(c);
c.resolve(this);
}
privatevoid addFakeClass(Number id, JavaClass c) {
fakeClasses.put(id, c);
addFakeClass(c);
}
privatesynchronizedvoid initNewObjects() { if (newObjects == null) { synchronized (this) { if (newObjects == null) {
newObjects = new HashMap<JavaHeapObject, Boolean>();
}
}
}
}
privatesynchronizedvoid initSiteTraces() { if (siteTraces == null) { synchronized (this) { if (siteTraces == null) {
siteTraces = new HashMap<JavaHeapObject, StackTrace>();
}
}
}
}
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.