630 lines · 19.9 KB · Java
RawDownload
/* * Copyright (c) 1997, 2008, 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. */ package com.sun.tools.hat.internal.model; import java.lang.ref.SoftReference;import java.util.*;import com.sun.tools.hat.internal.parser.ReadBuffer;import com.sun.tools.hat.internal.util.Misc; /** * * @author      Bill Foote */ /** * 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. */ public class Snapshot {     public static long SMALL_ID_MASK = 0x0FFFFFFFFL;    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];     private static final JavaField[] EMPTY_FIELD_ARRAY = new JavaField[0];    private static final 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>();     // name-to-class map    private Map<String, JavaClass> classes =                 new TreeMap<String, JavaClass>();     // new objects relative to a baseline - lazily initialized    private volatile Map<JavaHeapObject, Boolean> newObjects;     // allocation site traces for all objects - lazily initialized    private volatile Map<JavaHeapObject, StackTrace> siteTraces;     // object-to-Root map for all objects    private Map<JavaHeapObject, Root> rootsMap =                 new HashMap<JavaHeapObject, Root>();     // soft cache of finalizeable objects - lazily initialized    private SoftReference<Vector> finalizablesCache;     // represents null reference    private JavaThing nullThing;     // java.lang.ref.Reference class    private JavaClass weakReferenceClass;    // index of 'referent' field in java.lang.ref.Reference class    private int 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    private volatile 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    private boolean hasNewSet;    private boolean unresolvedObjectsOK;     // whether object array instances have new style class or    // old style (element) class.    private boolean newStyleArrayClass;     // object id size in the heap dump    private int 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).    private int minimumObjectSize;     public Snapshot(ReadBuffer buf) {        nullThing = new HackJavaValue("<null>", 0);        readBuf = buf;    }     public void setSiteTrace(JavaHeapObject obj, StackTrace trace) {        if (trace != null && trace.getFrames().length != 0) {            initSiteTraces();            siteTraces.put(obj, trace);        }    }     public StackTrace getSiteTrace(JavaHeapObject obj) {        if (siteTraces != null) {            return siteTraces.get(obj);        } else {            return null;        }    }     public void setNewStyleArrayClass(boolean value) {        newStyleArrayClass = value;    }     public boolean isNewStyleArrayClass() {        return newStyleArrayClass;    }     public void setIdentifierSize(int size) {        identifierSize = size;        minimumObjectSize = 2 * size;    }     public int getIdentifierSize() {        return identifierSize;    }     public int getMinimumObjectSize() {        return minimumObjectSize;    }     public void addHeapObject(long id, JavaHeapObject ho) {        heapObjects.put(makeId(id), ho);    }     public void addRoot(Root r) {        r.setIndex(roots.size());        roots.addElement(r);    }     public void 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()     */    public boolean getHasNewSet() {        return hasNewSet;    }     //    // Used in the body of resolve()    //    private static class MyVisitor extends AbstractJavaHeapObjectVisitor {        JavaHeapObject t;        public void visit(JavaHeapObject other) {            other.addReferenceFrom(t);        }    }     // To show heap parsing progress, we print a '.' after this limit    private static final int DOT_LIMIT = 5000;     /**     * Called after reading complete, to initialize the structure     */    public void 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);            }        }         heapObjects.putAll(fakeClasses);        fakeClasses.clear();         weakReferenceClass = findClass("java.lang.ref.Reference");        if (weakReferenceClass == null)  {      // JDK 1.1.x            weakReferenceClass = findClass("sun.misc.Ref");            referentFieldIndex = 0;        } else {            JavaField[] fields = weakReferenceClass.getFieldsForInstance();            for (int i = 0; i < fields.length; i++) {                if ("referent".equals(fields[i].getName())) {                    referentFieldIndex = i;                    break;                }            }        }         if (calculateRefs) {            calculateReferencesToObjects();            System.out.print("Eliminating duplicate references");            System.out.flush();            // This println refers to the *next* step        }        int count = 0;        for (JavaHeapObject t : heapObjects.values()) {            t.setupReferers();            ++count;            if (calculateRefs && count % DOT_LIMIT == 0) {                System.out.print(".");                System.out.flush();            }        }        if (calculateRefs) {            System.out.println("");        }         // to ensure that Iterator.remove() on getClasses()        // result will throw exception..        classes = Collections.unmodifiableMap(classes);    }     private void calculateReferencesToObjects() {        System.out.print("Chasing references, expect "                         + (heapObjects.size() / DOT_LIMIT) + " dots");        System.out.flush();        int count = 0;        MyVisitor visitor = new MyVisitor();        for (JavaHeapObject t : heapObjects.values()) {            visitor.t = t;            // call addReferenceFrom(t) on all objects t references:            t.visitReferencedObjects(visitor);            ++count;            if (count % DOT_LIMIT == 0) {                System.out.print(".");                System.out.flush();            }        }        System.out.println();        for (Root r : roots) {            r.resolve(this);            JavaHeapObject t = findThing(r.getId());            if (t != null) {                t.addReferenceFromRoot(r);            }        }    }     public void markNewRelativeTo(Snapshot baseline) {        hasNewSet = true;        for (JavaHeapObject t : heapObjects.values()) {            boolean isNew;            long thingID = t.getId();            if (thingID == 0L || thingID == -1L) {                isNew = false;            } else {                JavaThing other = baseline.findThing(t.getId());                if (other == null) {                    isNew = true;                } else {                    isNew = !t.isSameTypeAs(other);                }            }            t.setNew(isNew);        }    }     public Enumeration<JavaHeapObject> getThings() {        return heapObjects.elements();    }      public JavaHeapObject findThing(long id) {        Number idObj = makeId(id);        JavaHeapObject jho = heapObjects.get(idObj);        return jho != null? jho : fakeClasses.get(idObj);    }     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 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;    }     public synchronized Enumeration getFinalizerObjects() {        Vector obj;        if (finalizablesCache != null &&            (obj = finalizablesCache.get()) != null) {            return obj.elements();        }         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 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;    }     public boolean getUnresolvedObjectsOK() {        return unresolvedObjectsOK;    }     public void setUnresolvedObjectsOK(boolean v) {        unresolvedObjectsOK = v;    }     public JavaClass getWeakReferenceClass() {        return weakReferenceClass;    }     public int getReferentFieldIndex() {        return referentFieldIndex;    }     public JavaThing getNullThing() {        return nullThing;    }     public void setReachableExcludes(ReachableExcludes e) {        reachableExcludes = e;    } 

Lines 1–500 of 630.