0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: * The Original Software is NetBeans. The Initial Developer of the Original
0026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0027: * Microsystems, Inc. All Rights Reserved.
0028: *
0029: * If you wish your version of this file to be governed by only the CDDL
0030: * or only the GPL Version 2, indicate your decision by adding
0031: * "[Contributor] elects to include this software in this distribution
0032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0033: * single choice of license, a recipient has the option to distribute
0034: * your version of this file under either the CDDL, the GPL Version 2 or
0035: * to extend the choice of license to its licensees as provided above.
0036: * However, if you add GPL Version 2 code and therefore, elected the GPL
0037: * Version 2 license, then the option applies only if the new code is
0038: * made subject to such option by the copyright holder.
0039: */
0040:
0041: package org.netbeans.lib.profiler.heap;
0042:
0043: import java.io.File;
0044: import java.io.FileNotFoundException;
0045: import java.io.IOException;
0046: import java.util.ArrayList;
0047: import java.util.Collection;
0048: import java.util.Collections;
0049: import java.util.HashMap;
0050: import java.util.Iterator;
0051: import java.util.List;
0052: import java.util.Map;
0053: import java.util.Properties;
0054:
0055: /**
0056: *
0057: * @author Tomas Hurka
0058: */
0059: class HprofHeap implements Heap {
0060: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
0061:
0062: // dump tags
0063: static final int STRING = 1;
0064: static final int LOAD_CLASS = 2;
0065: private static final int UNLOAD_CLASS = 3;
0066: private static final int STACK_FRAME = 4;
0067: private static final int STACK_TRACE = 5;
0068: private static final int ALLOC_SITES = 6;
0069: static final int HEAP_SUMMARY = 7;
0070: private static final int START_THREAD = 0xa;
0071: private static final int END_THREAD = 0xb;
0072: private static final int HEAP_DUMP = 0xc;
0073: private static final int HEAP_DUMP_SEGMENT = 0x1c;
0074: private static final int HEAP_DUMP_END = 0x2c;
0075: private static final int CPU_SAMPLES = 0xd;
0076: private static final int CONTROL_SETTINGS = 0xe;
0077:
0078: // heap dump tags
0079: static final int ROOT_UNKNOWN = 0xff;
0080: static final int ROOT_JNI_GLOBAL = 1;
0081: static final int ROOT_JNI_LOCAL = 2;
0082: static final int ROOT_JAVA_FRAME = 3;
0083: static final int ROOT_NATIVE_STACK = 4;
0084: static final int ROOT_STICKY_CLASS = 5;
0085: static final int ROOT_THREAD_BLOCK = 6;
0086: static final int ROOT_MONITOR_USED = 7;
0087: static final int ROOT_THREAD_OBJECT = 8;
0088: static final int CLASS_DUMP = 0x20;
0089: private static final int INSTANCE_DUMP = 0x21;
0090: static final int OBJECT_ARRAY_DUMP = 0x22;
0091: static final int PRIMITIVE_ARRAY_DUMP = 0x23;
0092:
0093: // basic type
0094: static final int OBJECT = 2;
0095: static final int BOOLEAN = 4;
0096: static final int CHAR = 5;
0097: static final int FLOAT = 6;
0098: static final int DOUBLE = 7;
0099: static final int BYTE = 8;
0100: static final int SHORT = 9;
0101: static final int INT = 10;
0102: static final int LONG = 11;
0103: private static final boolean DEBUG = false;
0104:
0105: //~ Instance fields ----------------------------------------------------------------------------------------------------------
0106:
0107: HprofByteBuffer dumpBuffer;
0108: LongMap idToOffsetMap;
0109: NearestGCRoot nearestGCRoot;
0110: private ComputedSummary computedSummary;
0111: private Map gcRoots;
0112: private TagBounds allInstanceDumpBounds;
0113: private TagBounds headDumpSegment;
0114: private TagBounds[] heapTagBounds;
0115: private TagBounds[] tagBounds = new TagBounds[0xff];
0116: private boolean instancesCountComputed;
0117: private int idMapSize;
0118: private int segment;
0119:
0120: //~ Constructors -------------------------------------------------------------------------------------------------------------
0121:
0122: HprofHeap(File dumpFile, int seg) throws FileNotFoundException,
0123: IOException {
0124: dumpBuffer = HprofByteBuffer.createHprofByteBuffer(dumpFile);
0125: segment = seg;
0126: fillTagBounds(dumpBuffer.getHeaderSize());
0127: headDumpSegment = computeHeapDumpStart();
0128:
0129: if (headDumpSegment != null) {
0130: fillHeapTagBounds();
0131: }
0132:
0133: idToOffsetMap = new LongMap(idMapSize, dumpBuffer.getIDSize(),
0134: dumpBuffer.getFoffsetSize());
0135: nearestGCRoot = new NearestGCRoot(this );
0136: }
0137:
0138: //~ Methods ------------------------------------------------------------------------------------------------------------------
0139:
0140: public List /*<JavaClass>*/getAllClasses() {
0141: ClassDumpSegment classDumpBounds;
0142:
0143: if (headDumpSegment == null) {
0144: return Collections.EMPTY_LIST;
0145: }
0146:
0147: classDumpBounds = getClassDumpSegment();
0148:
0149: if (classDumpBounds == null) {
0150: return Collections.EMPTY_LIST;
0151: }
0152:
0153: return classDumpBounds.createClassCollection();
0154: }
0155:
0156: public GCRoot getGCRoot(Instance instance) {
0157: Long instanceId = Long.valueOf(instance.getInstanceId());
0158:
0159: if (gcRoots == null) {
0160: getGCRoots();
0161: }
0162:
0163: return (GCRoot) gcRoots.get(instanceId);
0164: }
0165:
0166: public Collection getGCRoots() {
0167: if (gcRoots == null) {
0168: gcRoots = computeGCRootsFor(heapTagBounds[ROOT_UNKNOWN]);
0169: gcRoots
0170: .putAll(computeGCRootsFor(heapTagBounds[ROOT_JNI_GLOBAL]));
0171: gcRoots
0172: .putAll(computeGCRootsFor(heapTagBounds[ROOT_JNI_LOCAL]));
0173: gcRoots
0174: .putAll(computeGCRootsFor(heapTagBounds[ROOT_JAVA_FRAME]));
0175: gcRoots
0176: .putAll(computeGCRootsFor(heapTagBounds[ROOT_NATIVE_STACK]));
0177: gcRoots
0178: .putAll(computeGCRootsFor(heapTagBounds[ROOT_STICKY_CLASS]));
0179: gcRoots
0180: .putAll(computeGCRootsFor(heapTagBounds[ROOT_THREAD_BLOCK]));
0181: gcRoots
0182: .putAll(computeGCRootsFor(heapTagBounds[ROOT_MONITOR_USED]));
0183: gcRoots
0184: .putAll(computeGCRootsFor(heapTagBounds[ROOT_THREAD_OBJECT]));
0185: }
0186:
0187: return gcRoots.values();
0188: }
0189:
0190: public Instance getInstanceByID(long instanceID) {
0191: if (instanceID == 0L) {
0192: return null;
0193: }
0194:
0195: ClassDump classDump;
0196: ClassDumpSegment classDumpBounds = getClassDumpSegment();
0197: int idSize = dumpBuffer.getIDSize();
0198: int instanceIdOffset = 0;
0199: int classIdOffset = 0;
0200: LongMap.Entry entry = idToOffsetMap.get(instanceID);
0201:
0202: if (entry == null) {
0203: return null;
0204: }
0205:
0206: long start = entry.getOffset();
0207: assert start != 0L;
0208:
0209: long[] offset = new long[] { start };
0210:
0211: int tag = readDumpTag(offset);
0212:
0213: if (tag == INSTANCE_DUMP) {
0214: instanceIdOffset = 1;
0215: classIdOffset = idSize + 4;
0216: } else if (tag == OBJECT_ARRAY_DUMP) {
0217: instanceIdOffset = 1;
0218: classIdOffset = idSize + 4 + 4;
0219: } else if (tag == PRIMITIVE_ARRAY_DUMP) {
0220: instanceIdOffset = 1;
0221: classIdOffset = idSize + 4 + 4;
0222: }
0223:
0224: if (tag == PRIMITIVE_ARRAY_DUMP) {
0225: classDump = classDumpBounds
0226: .getPrimitiveArrayClass(dumpBuffer.get(start + 1
0227: + classIdOffset));
0228:
0229: return new PrimitiveArrayDump(classDump, start);
0230: } else {
0231: long classId = dumpBuffer.getID(start + 1 + classIdOffset);
0232: classDump = classDumpBounds.getClassDumpByID(classId);
0233: }
0234:
0235: if (tag == INSTANCE_DUMP) {
0236: return new InstanceDump(classDump, start);
0237: } else if (tag == OBJECT_ARRAY_DUMP) {
0238: return new ObjectArrayDump(classDump, start);
0239: } else if (tag == CLASS_DUMP) {
0240: return new ClassDumpInstance(classDump);
0241: } else {
0242: throw new IllegalArgumentException("Illegal tag " + tag); // NOI18N
0243: }
0244: }
0245:
0246: public JavaClass getJavaClassByID(long javaclassId) {
0247: return getClassDumpSegment().getClassDumpByID(javaclassId);
0248: }
0249:
0250: public JavaClass getJavaClassByName(String fqn) {
0251: return getClassDumpSegment().getJavaClassByName(fqn);
0252: }
0253:
0254: public HeapSummary getSummary() {
0255: TagBounds summaryBound = tagBounds[HEAP_SUMMARY];
0256:
0257: if (summaryBound != null) {
0258: return new Summary(dumpBuffer, summaryBound.startOffset);
0259: }
0260:
0261: if (computedSummary == null) {
0262: computedSummary = new ComputedSummary(this );
0263: }
0264:
0265: return computedSummary;
0266: }
0267:
0268: public Properties getSystemProperties() {
0269: JavaClass systemClass = getJavaClassByName("java.lang.System"); // NOI18N
0270: Instance props = (Instance) systemClass
0271: .getValueOfStaticField("props"); //NOI18N
0272:
0273: return HprofProxy.getProperties(props);
0274: }
0275:
0276: ClassDumpSegment getClassDumpSegment() {
0277: return (ClassDumpSegment) heapTagBounds[CLASS_DUMP];
0278: }
0279:
0280: LoadClassSegment getLoadClassSegment() {
0281: return (LoadClassSegment) tagBounds[LOAD_CLASS];
0282: }
0283:
0284: StringSegment getStringSegment() {
0285: return (StringSegment) tagBounds[STRING];
0286: }
0287:
0288: int getValueSize(final byte type) {
0289: switch (type) {
0290: case HprofHeap.OBJECT:
0291: return dumpBuffer.getIDSize();
0292: case HprofHeap.BOOLEAN:
0293: return 1;
0294: case HprofHeap.CHAR:
0295: return 2;
0296: case HprofHeap.FLOAT:
0297: return 4;
0298: case HprofHeap.DOUBLE:
0299: return 8;
0300: case HprofHeap.BYTE:
0301: return 1;
0302: case HprofHeap.SHORT:
0303: return 2;
0304: case HprofHeap.INT:
0305: return 4;
0306: case HprofHeap.LONG:
0307: return 8;
0308: default:
0309: throw new IllegalArgumentException("Invalid type " + type); // NOI18N
0310: }
0311: }
0312:
0313: List /*<Instance>*/computeInstances(ClassDump cls) {
0314: int instancesCount = cls.getInstancesCount();
0315:
0316: if (instancesCount == 0) {
0317: return Collections.EMPTY_LIST;
0318: }
0319:
0320: long classId = cls.getJavaClassId();
0321: int idSize = dumpBuffer.getIDSize();
0322: List instances = new ArrayList(instancesCount);
0323: ClassDumpSegment classDumpBounds = getClassDumpSegment();
0324: long[] offset = new long[] { allInstanceDumpBounds.startOffset };
0325:
0326: while (offset[0] < allInstanceDumpBounds.endOffset) {
0327: long start = offset[0];
0328: int classIdOffset = 0;
0329: long instanceClassId = 0L;
0330: int tag = readDumpTag(offset);
0331: Instance instance;
0332:
0333: if (tag == INSTANCE_DUMP) {
0334: classIdOffset = idSize + 4;
0335: } else if (tag == OBJECT_ARRAY_DUMP) {
0336: classIdOffset = idSize + 4 + 4;
0337: } else if (tag == PRIMITIVE_ARRAY_DUMP) {
0338: byte type = dumpBuffer.get(start + 1 + idSize + 4 + 4);
0339: instanceClassId = classDumpBounds
0340: .getPrimitiveArrayClass(type).getJavaClassId();
0341: }
0342:
0343: if (classIdOffset != 0) {
0344: instanceClassId = dumpBuffer.getID(start + 1
0345: + classIdOffset);
0346: }
0347:
0348: if (instanceClassId == classId) {
0349: if (tag == INSTANCE_DUMP) {
0350: instance = new InstanceDump(cls, start);
0351: } else if (tag == OBJECT_ARRAY_DUMP) {
0352: instance = new ObjectArrayDump(cls, start);
0353: } else if (tag == PRIMITIVE_ARRAY_DUMP) {
0354: instance = new PrimitiveArrayDump(cls, start);
0355: } else {
0356: throw new IllegalArgumentException("Illegal tag "
0357: + tag); // NOI18N
0358: }
0359:
0360: instances.add(instance);
0361:
0362: if (--instancesCount == 0) {
0363: return instances;
0364: }
0365: }
0366: }
0367:
0368: if (DEBUG) {
0369: System.out.println("Class " + cls.getName() + " Col "
0370: + instances.size() + " instances "
0371: + cls.getInstancesCount()); // NOI18N
0372: }
0373:
0374: return instances;
0375: }
0376:
0377: void computeInstances() {
0378: if (instancesCountComputed) {
0379: return;
0380: }
0381:
0382: ClassDumpSegment classDumpBounds = getClassDumpSegment();
0383: int idSize = dumpBuffer.getIDSize();
0384: long[] offset = new long[] { allInstanceDumpBounds.startOffset };
0385: Map classIdToClassMap = classDumpBounds.getClassIdToClassMap();
0386:
0387: while (offset[0] < allInstanceDumpBounds.endOffset) {
0388: int classIdOffset = 0;
0389: int instanceIdOffset = 0;
0390: ClassDump classDump = null;
0391: long start = offset[0];
0392: int tag = readDumpTag(offset);
0393: long instanceId = 0L;
0394:
0395: if (tag == INSTANCE_DUMP) {
0396: instanceIdOffset = 1;
0397: classIdOffset = idSize + 4;
0398: } else if (tag == OBJECT_ARRAY_DUMP) {
0399: instanceIdOffset = 1;
0400: classIdOffset = idSize + 4 + 4;
0401: } else if (tag == PRIMITIVE_ARRAY_DUMP) {
0402: byte type = dumpBuffer.get(start + 1 + idSize + 4 + 4);
0403: instanceIdOffset = 1;
0404: classDump = classDumpBounds
0405: .getPrimitiveArrayClass(type);
0406: }
0407:
0408: if (instanceIdOffset != 0) {
0409: instanceId = dumpBuffer.getID(start + instanceIdOffset);
0410: idToOffsetMap.put(instanceId, start);
0411: }
0412:
0413: if (classIdOffset != 0) {
0414: long classId = dumpBuffer.getID(start + 1
0415: + classIdOffset);
0416: classDump = (ClassDump) classIdToClassMap.get(new Long(
0417: classId));
0418: }
0419:
0420: if (classDump != null) {
0421: classDump.incrementInstance();
0422: idToOffsetMap.get(instanceId).setIndex(
0423: classDump.getInstancesCount());
0424: classDumpBounds.addInstanceSize(classDump, tag, start);
0425: }
0426: }
0427:
0428: instancesCountComputed = true;
0429:
0430: return;
0431: }
0432:
0433: List findReferencesFor(long instanceId, byte[] idArray) {
0434: List refs = new ArrayList();
0435: ClassDumpSegment classDumpBounds = getClassDumpSegment();
0436: final int idSize = dumpBuffer.getIDSize();
0437: long[] offset = new long[] { allInstanceDumpBounds.startOffset };
0438:
0439: while (offset[0] < allInstanceDumpBounds.endOffset) {
0440: int classIdOffset = 0;
0441: int instanceIdOffset = 0;
0442: long start = offset[0];
0443: int tag = readDumpTag(offset);
0444:
0445: if (tag == INSTANCE_DUMP) {
0446: classIdOffset = idSize + 4;
0447:
0448: int size = dumpBuffer.getInt(start + 1 + idSize + 4
0449: + idSize);
0450: byte[] fields = new byte[size];
0451:
0452: dumpBuffer.get(start + 1 + idSize + 4 + idSize + 4,
0453: fields);
0454:
0455: if (contains(idArray, fields)) {
0456: long classId = dumpBuffer.getID(start + 1 + idSize
0457: + 4);
0458: ClassDump classDump = classDumpBounds
0459: .getClassDumpByID(classId);
0460: long foundInstanceId = dumpBuffer.getID(start + 1);
0461: InstanceDump instance = new InstanceDump(classDump,
0462: start);
0463: Iterator fieldIt = instance.getFieldValues()
0464: .iterator();
0465:
0466: while (fieldIt.hasNext()) {
0467: Object field = fieldIt.next();
0468:
0469: if (field instanceof HprofInstanceObjectValue) {
0470: HprofInstanceObjectValue objectValue = (HprofInstanceObjectValue) field;
0471:
0472: if (objectValue.getInstanceId() == instanceId) {
0473: refs.add(objectValue);
0474: }
0475: }
0476: }
0477: }
0478: } else if (tag == OBJECT_ARRAY_DUMP) {
0479: int elements = dumpBuffer
0480: .getInt(start + 1 + idSize + 4);
0481: int i;
0482: long position = start + 1 + idSize + 4 + 4 + idSize;
0483:
0484: for (i = 0; i < elements; i++, position += idSize) {
0485: if (dumpBuffer.getID(position) == instanceId) {
0486: long classId = dumpBuffer.getID(start + 1
0487: + idSize + 4 + 4);
0488: ClassDump classDump = classDumpBounds
0489: .getClassDumpByID(classId);
0490:
0491: refs.add(new HprofArrayValue(classDump, start,
0492: i));
0493: }
0494: }
0495: }
0496: }
0497:
0498: refs
0499: .addAll(classDumpBounds
0500: .findStaticReferencesFor(instanceId));
0501:
0502: return refs;
0503: }
0504:
0505: int readDumpTag(long[] offset) {
0506: long position = offset[0];
0507: int dumpTag = dumpBuffer.get(position++);
0508: int size = 0;
0509: long tagOffset = position;
0510: int idSize = dumpBuffer.getIDSize();
0511:
0512: switch (dumpTag) {
0513: case -1:
0514: case ROOT_UNKNOWN:
0515:
0516: if (DEBUG) {
0517: System.out.println("Tag ROOT_UNKNOWN"); // NOI18N
0518: }
0519:
0520: size = idSize;
0521: dumpTag = ROOT_UNKNOWN;
0522:
0523: break;
0524: case ROOT_JNI_GLOBAL:
0525:
0526: if (DEBUG) {
0527: System.out.println("Tag ROOT_JNI_GLOBAL"); // NOI18N
0528: }
0529:
0530: size = 2 * idSize;
0531:
0532: break;
0533: case ROOT_JNI_LOCAL: {
0534: if (DEBUG) {
0535: System.out.print("Tag ROOT_JNI_LOCAL"); // NOI18N
0536:
0537: long objId = dumpBuffer.getID(position);
0538: position += idSize;
0539:
0540: int threadSerial = dumpBuffer.getInt(position);
0541: position += 4;
0542:
0543: int frameNum = dumpBuffer.getInt(position);
0544: position += 4;
0545: System.out.println(" Object ID " + objId
0546: + " Thread serial " + threadSerial
0547: + " Frame num " + frameNum); // NOI18N
0548: }
0549:
0550: size = idSize + (2 * 4);
0551:
0552: break;
0553: }
0554: case ROOT_JAVA_FRAME:
0555:
0556: if (DEBUG) {
0557: System.out.println("Tag ROOT_JAVA_FRAME"); // NOI18N
0558: }
0559:
0560: size = idSize + (2 * 4);
0561:
0562: break;
0563: case ROOT_NATIVE_STACK:
0564:
0565: if (DEBUG) {
0566: System.out.println("Tag ROOT_NATIVE_STACK"); // NOI18N
0567: }
0568:
0569: size = idSize + 4;
0570:
0571: break;
0572: case ROOT_STICKY_CLASS:
0573:
0574: if (DEBUG) {
0575: System.out.println("Tag ROOT_STICKY_CLASS"); // NOI18N
0576: }
0577:
0578: size = idSize;
0579:
0580: break;
0581: case ROOT_THREAD_BLOCK:
0582:
0583: if (DEBUG) {
0584: System.out.println("Tag ROOT_THREAD_BLOCK"); // NOI18N
0585: }
0586:
0587: size = idSize + 4;
0588:
0589: break;
0590: case ROOT_MONITOR_USED:
0591:
0592: if (DEBUG) {
0593: System.out.println("Tag ROOT_MONITOR_USED"); // NOI18N
0594: }
0595:
0596: size = idSize;
0597:
0598: break;
0599: case ROOT_THREAD_OBJECT:
0600:
0601: if (DEBUG) {
0602: System.out.println("Tag ROOT_THREAD_OBJECT"); // NOI18N
0603: }
0604:
0605: size = idSize + (2 * 4);
0606:
0607: break;
0608: case CLASS_DUMP: {
0609: int constantSize = idSize + 4 + (6 * idSize) + 4;
0610: int cpoolSize;
0611: int sfSize;
0612: int ifSize;
0613:
0614: if (DEBUG) {
0615: System.out.println("Tag CLASS_DUMP, start offset "
0616: + tagOffset); // NOI18N
0617:
0618: long classId = dumpBuffer.getID(position);
0619: position += idSize;
0620:
0621: int stackSerial = dumpBuffer.getInt(position);
0622: position += 4;
0623:
0624: long super Id = dumpBuffer.getID(position);
0625: position += idSize;
0626:
0627: long classLoaderId = dumpBuffer.getID(position);
0628: position += idSize;
0629:
0630: long signersId = dumpBuffer.getID(position);
0631: position += idSize;
0632:
0633: long protDomainId = dumpBuffer.getID(position);
0634: position += idSize;
0635: dumpBuffer.getID(position);
0636: position += idSize;
0637: dumpBuffer.getID(position);
0638: position += idSize;
0639:
0640: int instSize = dumpBuffer.getInt(position);
0641: position += 4;
0642: cpoolSize = readConstantPool(offset);
0643: sfSize = readStaticFields(offset);
0644: ifSize = readInstanceFields(offset);
0645: System.out.println("ClassId " + classId
0646: + " stack Serial " + stackSerial + " Super ID "
0647: + super Id + " ClassLoader ID " + classLoaderId
0648: + " signers " + signersId + " Protect Dom Id "
0649: + protDomainId + " Size " + instSize); // NOI18N
0650: System.out.println(" Cpool " + cpoolSize
0651: + " Static fields " + sfSize
0652: + " Instance fileds " + ifSize); // NOI18N
0653: } else {
0654: offset[0] = position + constantSize;
0655: cpoolSize = readConstantPool(offset);
0656: sfSize = readStaticFields(offset);
0657: ifSize = readInstanceFields(offset);
0658: size = constantSize + cpoolSize + sfSize + ifSize;
0659: }
0660:
0661: break;
0662: }
0663: case INSTANCE_DUMP: {
0664: int fieldSize;
0665:
0666: if (DEBUG) {
0667: System.out.println("Tag INSTANCE_DUMP"); // NOI18N
0668:
0669: long objId = dumpBuffer.getID(position);
0670: position += idSize;
0671:
0672: int stackSerial = dumpBuffer.getInt(position);
0673: position += 4;
0674:
0675: long classId = dumpBuffer.getID(position);
0676: position += idSize;
0677: fieldSize = dumpBuffer.getInt(position);
0678: position += 4;
0679: System.out.println("Obj ID " + objId + " Stack serial "
0680: + stackSerial + " Class ID " + classId
0681: + " Field size " + fieldSize); // NOI18N
0682: } else {
0683: fieldSize = dumpBuffer.getInt(position + idSize + 4
0684: + idSize);
0685: }
0686:
0687: size = idSize + 4 + idSize + 4 + fieldSize;
0688:
0689: break;
0690: }
0691: case OBJECT_ARRAY_DUMP: {
0692: int elements;
0693:
0694: if (DEBUG) {
0695: System.out.println("Tag OBJECT_ARRAY_DUMP"); // NOI18N
0696:
0697: long objId = dumpBuffer.getID(position);
0698: position += idSize;
0699:
0700: int stackSerial = dumpBuffer.getInt(position);
0701: position += 4;
0702: elements = dumpBuffer.getInt(position);
0703: position += 4;
0704:
0705: long classId = dumpBuffer.getID(position);
0706: position += idSize;
0707:
0708: int dataSize = 0;
0709:
0710: if (DEBUG) {
0711: System.out.println("Obj ID " + objId
0712: + " Stack serial " + stackSerial
0713: + " Elements " + elements + " Type "
0714: + classId); // NOI18N
0715: }
0716:
0717: for (int i = 0; i < elements; i++) {
0718: dataSize += dumpBuffer.getIDSize();
0719: System.out.println("Instance ID "
0720: + dumpBuffer.getInt(position));
0721: position += 4; // NOI18N
0722: }
0723: } else {
0724: elements = dumpBuffer.getInt(position + idSize + 4);
0725: }
0726:
0727: size = idSize + 4 + 4 + idSize + (elements * idSize);
0728:
0729: break;
0730: }
0731: case PRIMITIVE_ARRAY_DUMP: {
0732: int elements;
0733: byte type;
0734:
0735: if (DEBUG) {
0736: System.out.println("Tag PRIMITINE_ARRAY_DUMP"); // NOI18N
0737:
0738: long objId = dumpBuffer.getID(position);
0739: position += idSize;
0740:
0741: int stackSerial = dumpBuffer.getInt(position);
0742: position += 4;
0743: elements = dumpBuffer.getInt(position);
0744: position += 4;
0745: type = dumpBuffer.get(position++);
0746:
0747: int dataSize = 0;
0748: System.out.println("Obj ID " + objId + " Stack serial "
0749: + stackSerial + " Elements " + elements
0750: + " Type " + type); // NOI18N
0751:
0752: for (int i = 0; i < elements; i++) {
0753: dataSize += getValueSize(type);
0754: }
0755: } else {
0756: elements = dumpBuffer.getInt(position + idSize + 4);
0757: type = dumpBuffer.get(position + idSize + 4 + 4);
0758: }
0759:
0760: size = idSize + 4 + 4 + 1 + (elements * getValueSize(type));
0761:
0762: break;
0763: }
0764: case HEAP_DUMP_SEGMENT: { // to handle big dumps
0765: size = 4 + 4;
0766:
0767: break;
0768: }
0769: default:
0770: throw new IllegalArgumentException("Invalid dump tag "
0771: + dumpTag + " at position " + (position - 1)); // NOI18N
0772: }
0773:
0774: offset[0] = tagOffset + size;
0775:
0776: return dumpTag;
0777: }
0778:
0779: int readTag(long[] offset) {
0780: long start = offset[0];
0781: int tag = dumpBuffer.get(start);
0782:
0783: //int time = dumpBuffer.getInt(start+1);
0784: long len = dumpBuffer.getInt(start + 1 + 4) & 0xFFFFFFFFL; // len is unsigned int
0785: offset[0] = start + 1 + 4 + 4 + len;
0786:
0787: return tag;
0788: }
0789:
0790: private Map computeGCRootsFor(TagBounds tagBounds) {
0791: Map roots = new HashMap();
0792:
0793: if (tagBounds != null) {
0794: int rootTag = tagBounds.tag;
0795: long[] offset = new long[] { tagBounds.startOffset };
0796:
0797: while (offset[0] < tagBounds.endOffset) {
0798: long start = offset[0];
0799:
0800: if (readDumpTag(offset) == rootTag) {
0801: HprofGCRoot root = new HprofGCRoot(this , start);
0802: roots.put(Long.valueOf(root.getInstanceId()), root);
0803: }
0804: }
0805: }
0806:
0807: return roots;
0808: }
0809:
0810: private TagBounds computeHeapDumpStart() throws IOException {
0811: TagBounds heapDumpBounds = tagBounds[HEAP_DUMP];
0812:
0813: if (heapDumpBounds != null) {
0814: long start = heapDumpBounds.startOffset;
0815: long[] offset = new long[] { start };
0816:
0817: for (int i = 0; (i <= segment)
0818: && (start < heapDumpBounds.endOffset);) {
0819: int tag = readTag(offset);
0820:
0821: if (tag == HEAP_DUMP) {
0822: if (i == segment) {
0823: return new TagBounds(HEAP_DUMP, start,
0824: offset[0]);
0825: } else {
0826: i++;
0827: }
0828: }
0829:
0830: start = offset[0];
0831: }
0832:
0833: throw new IOException("Invalid segment " + segment); // NOI18N
0834: } else {
0835: TagBounds heapDumpSegmentBounds = tagBounds[HEAP_DUMP_SEGMENT];
0836:
0837: if (heapDumpSegmentBounds != null) {
0838: long start = heapDumpSegmentBounds.startOffset;
0839: long end = heapDumpSegmentBounds.endOffset;
0840:
0841: return new TagBounds(HEAP_DUMP, start, end);
0842: }
0843: }
0844:
0845: return null;
0846: }
0847:
0848: private boolean contains(byte[] idArray, byte[] fields) {
0849: int fieldIndex;
0850: byte firstIndexByte = idArray[0];
0851:
0852: for (fieldIndex = 0; fieldIndex < (fields.length
0853: - idArray.length + 1); fieldIndex++) {
0854: if (fields[fieldIndex] == firstIndexByte) {
0855: int idIndex;
0856:
0857: for (idIndex = 1; idIndex < idArray.length; idIndex++) {
0858: if (idArray[idIndex] != fields[fieldIndex + idIndex]) {
0859: break;
0860: }
0861: }
0862:
0863: if (idIndex == idArray.length) {
0864: return true;
0865: }
0866: }
0867: }
0868:
0869: return false;
0870: }
0871:
0872: private void fillHeapTagBounds() {
0873: if (heapTagBounds != null) {
0874: return;
0875: }
0876:
0877: heapTagBounds = new TagBounds[0x100];
0878:
0879: long[] offset = new long[] { headDumpSegment.startOffset + 1 + 4 + 4 };
0880:
0881: while (offset[0] < headDumpSegment.endOffset) {
0882: long start = offset[0];
0883: int tag = readDumpTag(offset);
0884: TagBounds bounds = heapTagBounds[tag];
0885: long end = offset[0];
0886:
0887: if (bounds == null) {
0888: TagBounds newBounds;
0889:
0890: if (tag == CLASS_DUMP) {
0891: newBounds = new ClassDumpSegment(this , start, end);
0892: } else {
0893: newBounds = new TagBounds(tag, start, end);
0894: }
0895:
0896: heapTagBounds[tag] = newBounds;
0897: } else {
0898: bounds.endOffset = end;
0899: }
0900:
0901: if ((tag == CLASS_DUMP) || (tag == INSTANCE_DUMP)
0902: || (tag == OBJECT_ARRAY_DUMP)
0903: || (tag == PRIMITIVE_ARRAY_DUMP)) {
0904: idMapSize++;
0905: }
0906: }
0907:
0908: TagBounds instanceDumpBounds = heapTagBounds[INSTANCE_DUMP];
0909: TagBounds objArrayDumpBounds = heapTagBounds[OBJECT_ARRAY_DUMP];
0910: TagBounds primArrayDumpBounds = heapTagBounds[PRIMITIVE_ARRAY_DUMP];
0911: allInstanceDumpBounds = instanceDumpBounds
0912: .union(objArrayDumpBounds);
0913: allInstanceDumpBounds = allInstanceDumpBounds
0914: .union(primArrayDumpBounds);
0915: }
0916:
0917: private void fillTagBounds(long tagStart) {
0918: long[] offset = new long[] { tagStart };
0919:
0920: while (offset[0] < dumpBuffer.capacity()) {
0921: long start = offset[0];
0922: int tag = readTag(offset);
0923: TagBounds bounds = tagBounds[tag];
0924: long end = offset[0];
0925:
0926: if (bounds == null) {
0927: TagBounds newBounds;
0928:
0929: if (tag == LOAD_CLASS) {
0930: newBounds = new LoadClassSegment(this , start, end);
0931: } else if (tag == STRING) {
0932: newBounds = new StringSegment(this , start, end);
0933: } else {
0934: newBounds = new TagBounds(tag, start, end);
0935: }
0936:
0937: tagBounds[tag] = newBounds;
0938: } else {
0939: bounds.endOffset = end;
0940: }
0941: }
0942: }
0943:
0944: private int readConstantPool(long[] offset) {
0945: long start = offset[0];
0946: int size = dumpBuffer.getShort(start);
0947: offset[0] += 2;
0948:
0949: for (int i = 0; i < size; i++) {
0950: offset[0] += 2;
0951: readValue(offset);
0952: }
0953:
0954: return (int) (offset[0] - start);
0955: }
0956:
0957: private int readInstanceFields(long[] offset) {
0958: long position = offset[0];
0959: int fields = dumpBuffer.getShort(offset[0]);
0960: offset[0] += 2;
0961:
0962: if (DEBUG) {
0963: for (int i = 0; i < fields; i++) {
0964: long nameId = dumpBuffer.getID(offset[0]);
0965: offset[0] += dumpBuffer.getIDSize();
0966:
0967: byte type = dumpBuffer.get(offset[0]++);
0968: System.out.println("Instance field name ID " + nameId
0969: + " Type " + type); // NOI18N
0970: }
0971: } else {
0972: offset[0] += (fields * (dumpBuffer.getIDSize() + 1));
0973: }
0974:
0975: return (int) (offset[0] - position);
0976: }
0977:
0978: private int readStaticFields(long[] offset) {
0979: long start = offset[0];
0980: int fields = dumpBuffer.getShort(start);
0981: offset[0] += 2;
0982:
0983: int idSize = dumpBuffer.getIDSize();
0984:
0985: for (int i = 0; i < fields; i++) {
0986: if (DEBUG) {
0987: long nameId = dumpBuffer.getID(offset[0]);
0988: System.out
0989: .print("Static field name ID " + nameId + " "); // NOI18N
0990: }
0991:
0992: offset[0] += idSize;
0993:
0994: byte type = readValue(offset);
0995: }
0996:
0997: return (int) (offset[0] - start);
0998: }
0999:
1000: private byte readValue(long[] offset) {
1001: byte type = dumpBuffer.get(offset[0]++);
1002: offset[0] += getValueSize(type);
1003:
1004: return type;
1005: }
1006: }
|