Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
41161 views
/*1* Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.utilities;2526import java.io.*;27import java.nio.ByteBuffer;28import java.nio.ByteOrder;29import java.nio.channels.*;30import java.util.*;31import java.util.zip.*;32import sun.jvm.hotspot.debugger.*;33import sun.jvm.hotspot.memory.*;34import sun.jvm.hotspot.oops.*;35import sun.jvm.hotspot.runtime.*;36import sun.jvm.hotspot.classfile.*;37import sun.jvm.hotspot.gc.z.ZCollectedHeap;3839/*40* This class writes Java heap in hprof binary format. This format is41* used by Heap Analysis Tool (HAT). The class is heavily influenced42* by 'hprof_io.c' of 1.5 new hprof implementation.43*/4445/* hprof binary format: (result either written to a file or sent over46* the network).47*48* WARNING: This format is still under development, and is subject to49* change without notice.50*51* header "JAVA PROFILE 1.0.2" (0-terminated)52* u4 size of identifiers. Identifiers are used to represent53* UTF8 strings, objects, stack traces, etc. They usually54* have the same size as host pointers. For example, on55* Solaris and Win32, the size is 4.56* u4 high word57* u4 low word number of milliseconds since 0:00 GMT, 1/1/7058* [record]* a sequence of records.59*60*/6162/*63*64* Record format:65*66* u1 a TAG denoting the type of the record67* u4 number of *microseconds* since the time stamp in the68* header. (wraps around in a little more than an hour)69* u4 number of bytes *remaining* in the record. Note that70* this number excludes the tag and the length field itself.71* [u1]* BODY of the record (a sequence of bytes)72*/7374/*75* The following TAGs are supported:76*77* TAG BODY notes78*----------------------------------------------------------79* HPROF_UTF8 a UTF8-encoded name80*81* id name ID82* [u1]* UTF8 characters (no trailing zero)83*84* HPROF_LOAD_CLASS a newly loaded class85*86* u4 class serial number (> 0)87* id class object ID88* u4 stack trace serial number89* id class name ID90*91* HPROF_UNLOAD_CLASS an unloading class92*93* u4 class serial_number94*95* HPROF_FRAME a Java stack frame96*97* id stack frame ID98* id method name ID99* id method signature ID100* id source file name ID101* u4 class serial number102* i4 line number. >0: normal103* -1: unknown104* -2: compiled method105* -3: native method106*107* HPROF_TRACE a Java stack trace108*109* u4 stack trace serial number110* u4 thread serial number111* u4 number of frames112* [id]* stack frame IDs113*114*115* HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC116*117* u2 flags 0x0001: incremental vs. complete118* 0x0002: sorted by allocation vs. live119* 0x0004: whether to force a GC120* u4 cutoff ratio121* u4 total live bytes122* u4 total live instances123* u8 total bytes allocated124* u8 total instances allocated125* u4 number of sites that follow126* [u1 is_array: 0: normal object127* 2: object array128* 4: boolean array129* 5: char array130* 6: float array131* 7: double array132* 8: byte array133* 9: short array134* 10: int array135* 11: long array136* u4 class serial number (may be zero during startup)137* u4 stack trace serial number138* u4 number of bytes alive139* u4 number of instances alive140* u4 number of bytes allocated141* u4]* number of instance allocated142*143* HPROF_START_THREAD a newly started thread.144*145* u4 thread serial number (> 0)146* id thread object ID147* u4 stack trace serial number148* id thread name ID149* id thread group name ID150* id thread group parent name ID151*152* HPROF_END_THREAD a terminating thread.153*154* u4 thread serial number155*156* HPROF_HEAP_SUMMARY heap summary157*158* u4 total live bytes159* u4 total live instances160* u8 total bytes allocated161* u8 total instances allocated162*163* HPROF_HEAP_DUMP denote a heap dump164*165* [heap dump sub-records]*166*167* There are four kinds of heap dump sub-records:168*169* u1 sub-record type170*171* HPROF_GC_ROOT_UNKNOWN unknown root172*173* id object ID174*175* HPROF_GC_ROOT_THREAD_OBJ thread object176*177* id thread object ID (may be 0 for a178* thread newly attached through JNI)179* u4 thread sequence number180* u4 stack trace sequence number181*182* HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root183*184* id object ID185* id JNI global ref ID186*187* HPROF_GC_ROOT_JNI_LOCAL JNI local ref188*189* id object ID190* u4 thread serial number191* u4 frame # in stack trace (-1 for empty)192*193* HPROF_GC_ROOT_JAVA_FRAME Java stack frame194*195* id object ID196* u4 thread serial number197* u4 frame # in stack trace (-1 for empty)198*199* HPROF_GC_ROOT_NATIVE_STACK Native stack200*201* id object ID202* u4 thread serial number203*204* HPROF_GC_ROOT_STICKY_CLASS System class205*206* id object ID207*208* HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block209*210* id object ID211* u4 thread serial number212*213* HPROF_GC_ROOT_MONITOR_USED Busy monitor214*215* id object ID216*217* HPROF_GC_CLASS_DUMP dump of a class object218*219* id class object ID220* u4 stack trace serial number221* id super class object ID222* id class loader object ID223* id signers object ID224* id protection domain object ID225* id reserved226* id reserved227*228* u4 instance size (in bytes)229*230* u2 size of constant pool231* [u2, constant pool index,232* ty, type233* 2: object234* 4: boolean235* 5: char236* 6: float237* 7: double238* 8: byte239* 9: short240* 10: int241* 11: long242* vl]* and value243*244* u2 number of static fields245* [id, static field name,246* ty, type,247* vl]* and value248*249* u2 number of inst. fields (not inc. super)250* [id, instance field name,251* ty]* type252*253* HPROF_GC_INSTANCE_DUMP dump of a normal object254*255* id object ID256* u4 stack trace serial number257* id class object ID258* u4 number of bytes that follow259* [vl]* instance field values (class, followed260* by super, super's super ...)261*262* HPROF_GC_OBJ_ARRAY_DUMP dump of an object array263*264* id array object ID265* u4 stack trace serial number266* u4 number of elements267* id array class ID268* [id]* elements269*270* HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array271*272* id array object ID273* u4 stack trace serial number274* u4 number of elements275* u1 element type276* 4: boolean array277* 5: char array278* 6: float array279* 7: double array280* 8: byte array281* 9: short array282* 10: int array283* 11: long array284* [u1]* elements285*286* HPROF_CPU_SAMPLES a set of sample traces of running threads287*288* u4 total number of samples289* u4 # of traces290* [u4 # of samples291* u4]* stack trace serial number292*293* HPROF_CONTROL_SETTINGS the settings of on/off switches294*295* u4 0x00000001: alloc traces on/off296* 0x00000002: cpu sampling on/off297* u2 stack trace depth298*299*300* A heap dump can optionally be generated as a sequence of heap dump301* segments. This sequence is terminated by an end record. The additional302* tags allowed by format "JAVA PROFILE 1.0.2" are:303*304* HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment305*306* [heap dump sub-records]*307* The same sub-record types allowed by HPROF_HEAP_DUMP308*309* HPROF_HEAP_DUMP_END denotes the end of a heap dump310*311*/312313public class HeapHprofBinWriter extends AbstractHeapGraphWriter {314315// Record which Symbol names have been dumped already.316private HashSet<Symbol> names;317318private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000;319320// The approximate size of a heap segment. Used to calculate when to create321// a new segment.322private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000;323324// hprof binary file header325private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2";326327// constants in enum HprofTag328private static final int HPROF_UTF8 = 0x01;329private static final int HPROF_LOAD_CLASS = 0x02;330private static final int HPROF_UNLOAD_CLASS = 0x03;331private static final int HPROF_FRAME = 0x04;332private static final int HPROF_TRACE = 0x05;333private static final int HPROF_ALLOC_SITES = 0x06;334private static final int HPROF_HEAP_SUMMARY = 0x07;335private static final int HPROF_START_THREAD = 0x0A;336private static final int HPROF_END_THREAD = 0x0B;337private static final int HPROF_HEAP_DUMP = 0x0C;338private static final int HPROF_CPU_SAMPLES = 0x0D;339private static final int HPROF_CONTROL_SETTINGS = 0x0E;340341// 1.0.2 record types342private static final int HPROF_HEAP_DUMP_SEGMENT = 0x1C;343private static final int HPROF_HEAP_DUMP_END = 0x2C;344345// Heap dump constants346// constants in enum HprofGcTag347private static final int HPROF_GC_ROOT_UNKNOWN = 0xFF;348private static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01;349private static final int HPROF_GC_ROOT_JNI_LOCAL = 0x02;350private static final int HPROF_GC_ROOT_JAVA_FRAME = 0x03;351private static final int HPROF_GC_ROOT_NATIVE_STACK = 0x04;352private static final int HPROF_GC_ROOT_STICKY_CLASS = 0x05;353private static final int HPROF_GC_ROOT_THREAD_BLOCK = 0x06;354private static final int HPROF_GC_ROOT_MONITOR_USED = 0x07;355private static final int HPROF_GC_ROOT_THREAD_OBJ = 0x08;356private static final int HPROF_GC_CLASS_DUMP = 0x20;357private static final int HPROF_GC_INSTANCE_DUMP = 0x21;358private static final int HPROF_GC_OBJ_ARRAY_DUMP = 0x22;359private static final int HPROF_GC_PRIM_ARRAY_DUMP = 0x23;360361// constants in enum HprofType362private static final int HPROF_ARRAY_OBJECT = 1;363private static final int HPROF_NORMAL_OBJECT = 2;364private static final int HPROF_BOOLEAN = 4;365private static final int HPROF_CHAR = 5;366private static final int HPROF_FLOAT = 6;367private static final int HPROF_DOUBLE = 7;368private static final int HPROF_BYTE = 8;369private static final int HPROF_SHORT = 9;370private static final int HPROF_INT = 10;371private static final int HPROF_LONG = 11;372373// Java type codes374private static final int JVM_SIGNATURE_BOOLEAN = 'Z';375private static final int JVM_SIGNATURE_CHAR = 'C';376private static final int JVM_SIGNATURE_BYTE = 'B';377private static final int JVM_SIGNATURE_SHORT = 'S';378private static final int JVM_SIGNATURE_INT = 'I';379private static final int JVM_SIGNATURE_LONG = 'J';380private static final int JVM_SIGNATURE_FLOAT = 'F';381private static final int JVM_SIGNATURE_DOUBLE = 'D';382private static final int JVM_SIGNATURE_ARRAY = '[';383private static final int JVM_SIGNATURE_CLASS = 'L';384385private static final long MAX_U4_VALUE = 0xFFFFFFFFL;386int serialNum = 1;387388public HeapHprofBinWriter() {389this.KlassMap = new ArrayList<Klass>();390this.names = new HashSet<Symbol>();391this.gzLevel = 0;392}393394public HeapHprofBinWriter(int gzLevel) {395this.KlassMap = new ArrayList<Klass>();396this.names = new HashSet<Symbol>();397this.gzLevel = gzLevel;398}399400public synchronized void write(String fileName) throws IOException {401VM vm = VM.getVM();402403// Check whether we should dump the heap as segments404useSegmentedHeapDump = isCompression() ||405(vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD);406407// open file stream and create buffered data output stream408fos = new FileOutputStream(fileName);409hprofBufferedOut = null;410OutputStream dataOut = fos;411if (useSegmentedHeapDump) {412if (isCompression()) {413dataOut = new GZIPOutputStream(fos) {414{415this.def.setLevel(gzLevel);416}417};418}419hprofBufferedOut = new SegmentedOutputStream(dataOut);420} else {421hprofBufferedOut = new SegmentedOutputStream(fos, false /* allowSegmented */);422}423out = new DataOutputStream(hprofBufferedOut);424dbg = vm.getDebugger();425objectHeap = vm.getObjectHeap();426427OBJ_ID_SIZE = (int) vm.getOopSize();428429BOOLEAN_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BOOLEAN);430BYTE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BYTE);431CHAR_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_CHAR);432SHORT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_SHORT);433INT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_INT);434LONG_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_LONG);435FLOAT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_FLOAT);436DOUBLE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_DOUBLE);437OBJECT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_OBJECT);438439BOOLEAN_SIZE = objectHeap.getBooleanSize();440BYTE_SIZE = objectHeap.getByteSize();441CHAR_SIZE = objectHeap.getCharSize();442SHORT_SIZE = objectHeap.getShortSize();443INT_SIZE = objectHeap.getIntSize();444LONG_SIZE = objectHeap.getLongSize();445FLOAT_SIZE = objectHeap.getFloatSize();446DOUBLE_SIZE = objectHeap.getDoubleSize();447448// hprof bin format header449writeFileHeader();450451// dummy stack trace without any frames so that452// HAT can be run without -stack false option453writeDummyTrace();454455// hprof UTF-8 symbols section456writeSymbols();457458// HPROF_LOAD_CLASS records for all classes459writeClasses();460461// write HPROF_FRAME and HPROF_TRACE records462dumpStackTraces();463464// write CLASS_DUMP records465writeClassDumpRecords();466467// this will write heap data into the buffer stream468super.write();469470// flush buffer stream.471out.flush();472473if (!useSegmentedHeapDump) {474// Fill in final length.475fillInHeapRecordLength();476} else {477hprofBufferedOut.finish();478// Write heap segment-end record479out.writeByte((byte) HPROF_HEAP_DUMP_END);480out.writeInt(0);481out.writeInt(0);482}483484// flush buffer stream and throw it.485out.flush();486out.close();487out = null;488hprofBufferedOut = null;489}490491@Override492protected void writeHeapRecordPrologue() throws IOException {493if (useSegmentedHeapDump) {494hprofBufferedOut.enterSegmentMode();495} else if (currentSegmentStart == 0) {496// write heap data header497out.writeByte((byte) (HPROF_HEAP_DUMP));498out.writeInt(0);499500// remember position of dump length, we will fixup501// length later - hprof format requires length.502out.flush();503currentSegmentStart = fos.getChannel().position();504// write dummy length of 0 and we'll fix it later.505out.writeInt(0);506}507}508509@Override510protected void writeHeapRecordEpilogue() throws IOException {511if (useSegmentedHeapDump) {512hprofBufferedOut.exitSegmentMode();513}514}515516private void fillInHeapRecordLength() throws IOException {517assert !useSegmentedHeapDump : "fillInHeapRecordLength is not supported for segmented heap dump";518519// now get the current position to calculate length520long dumpEnd = fos.getChannel().position();521522// calculate the length of heap data523long dumpLenLong = (dumpEnd - currentSegmentStart - 4L);524525// Check length boundary, overflow could happen but is _very_ unlikely526if (dumpLenLong >= (4L * 0x40000000)) {527throw new RuntimeException("Heap segment size overflow.");528}529530// Save the current position531long currentPosition = fos.getChannel().position();532533// seek the position to write length534fos.getChannel().position(currentSegmentStart);535536// write length537int dumpLen = (int) dumpLenLong;538byte[] lenBytes = genByteArrayFromInt(dumpLen);539fos.write(lenBytes);540541//Reset to previous current position542fos.getChannel().position(currentPosition);543}544545// get the size in bytes for the requested type546private long getSizeForType(int type) throws IOException {547switch (type) {548case TypeArrayKlass.T_BOOLEAN:549return BOOLEAN_SIZE;550case TypeArrayKlass.T_INT:551return INT_SIZE;552case TypeArrayKlass.T_CHAR:553return CHAR_SIZE;554case TypeArrayKlass.T_SHORT:555return SHORT_SIZE;556case TypeArrayKlass.T_BYTE:557return BYTE_SIZE;558case TypeArrayKlass.T_LONG:559return LONG_SIZE;560case TypeArrayKlass.T_FLOAT:561return FLOAT_SIZE;562case TypeArrayKlass.T_DOUBLE:563return DOUBLE_SIZE;564default:565throw new RuntimeException(566"Should not reach here: Unknown type: " + type);567}568}569570private int getArrayHeaderSize(boolean isObjectAarray) {571return isObjectAarray?572((int) BYTE_SIZE + 2 * (int) INT_SIZE + 2 * (int) OBJ_ID_SIZE):573(2 * (int) BYTE_SIZE + 2 * (int) INT_SIZE + (int) OBJ_ID_SIZE);574}575576// Check if we need to truncate an array577private int calculateArrayMaxLength(long originalArrayLength,578int headerSize,579long typeSize,580String typeName) throws IOException {581582long length = originalArrayLength;583584// now get the current position to calculate length585long dumpEnd = fos.getChannel().position();586long originalLengthInBytes = originalArrayLength * typeSize;587588// calculate the length of heap data589// only process when segmented heap dump is not used, since SegmentedOutputStream590// could create segment automatically.591long currentRecordLength = (dumpEnd - currentSegmentStart - 4L);592if ((!useSegmentedHeapDump) && currentRecordLength > 0 &&593(currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) {594fillInHeapRecordLength();595currentSegmentStart = 0;596writeHeapRecordPrologue();597currentRecordLength = 0;598}599600// Calculate the max bytes we can use.601long maxBytes = (MAX_U4_VALUE - (headerSize + currentRecordLength));602603if (originalLengthInBytes > maxBytes) {604length = maxBytes/typeSize;605System.err.println("WARNING: Cannot dump array of type " + typeName606+ " with length " + originalArrayLength607+ "; truncating to length " + length);608}609return (int) length;610}611612private void writeClassDumpRecords() throws IOException {613ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();614try {615cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {616public void visit(Klass k) {617try {618writeHeapRecordPrologue();619writeClassDumpRecord(k);620writeHeapRecordEpilogue();621} catch (IOException e) {622throw new RuntimeException(e);623}624}625});626} catch (RuntimeException re) {627handleRuntimeException(re);628}629}630631protected void writeClass(Instance instance) throws IOException {632Klass reflectedKlass = java_lang_Class.asKlass(instance);633// dump instance record only for primitive type Class objects.634// all other Class objects are covered by writeClassDumpRecords.635if (reflectedKlass == null) {636writeInstance(instance);637}638}639640private void writeClassDumpRecord(Klass k) throws IOException {641out.writeByte((byte)HPROF_GC_CLASS_DUMP);642writeObjectID(k.getJavaMirror());643out.writeInt(DUMMY_STACK_TRACE_ID);644Klass superKlass = k.getJavaSuper();645if (superKlass != null) {646writeObjectID(superKlass.getJavaMirror());647} else {648writeObjectID(null);649}650651if (k instanceof InstanceKlass) {652InstanceKlass ik = (InstanceKlass) k;653writeObjectID(ik.getClassLoader());654writeObjectID(null); // ik.getJavaMirror().getSigners());655writeObjectID(null); // ik.getJavaMirror().getProtectionDomain());656// two reserved id fields657writeObjectID(null);658writeObjectID(null);659List<Field> fields = getInstanceFields(ik);660int instSize = getSizeForFields(fields);661classDataCache.put(ik, new ClassData(instSize, fields));662out.writeInt(instSize);663664// For now, ignore constant pool - HAT ignores too!665// output number of cp entries as zero.666out.writeShort((short) 0);667668List<Field> declaredFields = ik.getImmediateFields();669List<Field> staticFields = new ArrayList<>();670List<Field> instanceFields = new ArrayList<>();671Iterator<Field> itr = null;672for (itr = declaredFields.iterator(); itr.hasNext();) {673Field field = itr.next();674if (field.isStatic()) {675staticFields.add(field);676} else {677instanceFields.add(field);678}679}680681// dump static field descriptors682writeFieldDescriptors(staticFields, ik);683684// dump instance field descriptors685writeFieldDescriptors(instanceFields, null);686} else {687if (k instanceof ObjArrayKlass) {688ObjArrayKlass oak = (ObjArrayKlass) k;689Klass bottomKlass = oak.getBottomKlass();690if (bottomKlass instanceof InstanceKlass) {691InstanceKlass ik = (InstanceKlass) bottomKlass;692writeObjectID(ik.getClassLoader());693writeObjectID(null); // ik.getJavaMirror().getSigners());694writeObjectID(null); // ik.getJavaMirror().getProtectionDomain());695} else {696writeObjectID(null);697writeObjectID(null);698writeObjectID(null);699}700} else {701writeObjectID(null);702writeObjectID(null);703writeObjectID(null);704}705// two reserved id fields706writeObjectID(null);707writeObjectID(null);708// write zero instance size -- as instance size709// is variable for arrays.710out.writeInt(0);711// no constant pool for array klasses712out.writeShort((short) 0);713// no static fields for array klasses714out.writeShort((short) 0);715// no instance fields for array klasses716out.writeShort((short) 0);717}718}719720private void dumpStackTraces() throws IOException {721// write a HPROF_TRACE record without any frames to be referenced as object alloc sites722writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE );723out.writeInt(DUMMY_STACK_TRACE_ID);724out.writeInt(0); // thread number725out.writeInt(0); // frame count726727int frameSerialNum = 0;728int numThreads = 0;729Threads threads = VM.getVM().getThreads();730for (int i = 0; i < threads.getNumberOfThreads(); i++) {731JavaThread thread = threads.getJavaThreadAt(i);732Oop threadObj = thread.getThreadObj();733if (threadObj != null && !thread.isExiting() && !thread.isHiddenFromExternalView()) {734735// dump thread stack trace736ThreadStackTrace st = new ThreadStackTrace(thread);737st.dumpStack(-1);738numThreads++;739740// write HPROF_FRAME records for this thread's stack trace741int depth = st.getStackDepth();742int threadFrameStart = frameSerialNum;743for (int j=0; j < depth; j++) {744StackFrameInfo frame = st.stackFrameAt(j);745Method m = frame.getMethod();746int classSerialNum = KlassMap.indexOf(m.getMethodHolder()) + 1;747// the class serial number starts from 1748assert classSerialNum > 0:"class not found";749dumpStackFrame(++frameSerialNum, classSerialNum, m, frame.getBCI());750}751752// write HPROF_TRACE record for one thread753writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE + depth * (int)VM.getVM().getOopSize());754int stackSerialNum = numThreads + DUMMY_STACK_TRACE_ID;755out.writeInt(stackSerialNum); // stack trace serial number756out.writeInt(numThreads); // thread serial number757out.writeInt(depth); // frame count758for (int j=1; j <= depth; j++) {759writeObjectID(threadFrameStart + j);760}761}762}763}764765private void dumpStackFrame(int frameSN, int classSN, Method m, int bci) throws IOException {766int lineNumber;767if (m.isNative()) {768lineNumber = -3; // native frame769} else {770lineNumber = m.getLineNumberFromBCI(bci);771}772// First dump UTF8 if needed773writeSymbol(m.getName()); // method's name774writeSymbol(m.getSignature()); // method's signature775writeSymbol(m.getMethodHolder().getSourceFileName()); // source file name776// Then write FRAME descriptor777writeHeader(HPROF_FRAME, 4 * (int)VM.getVM().getOopSize() + 2 * (int)INT_SIZE);778writeObjectID(frameSN); // frame serial number779writeSymbolID(m.getName()); // method's name780writeSymbolID(m.getSignature()); // method's signature781writeSymbolID(m.getMethodHolder().getSourceFileName()); // source file name782out.writeInt(classSN); // class serial number783out.writeInt(lineNumber); // line number784}785786protected void writeJavaThread(JavaThread jt, int index) throws IOException {787out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ);788writeObjectID(jt.getThreadObj());789out.writeInt(index);790out.writeInt(DUMMY_STACK_TRACE_ID);791writeLocalJNIHandles(jt, index);792}793794protected void writeLocalJNIHandles(JavaThread jt, int index) throws IOException {795final int threadIndex = index;796JNIHandleBlock blk = jt.activeHandles();797if (blk != null) {798try {799blk.oopsDo(new AddressVisitor() {800public void visitAddress(Address handleAddr) {801try {802if (handleAddr != null) {803OopHandle oopHandle = handleAddr.getOopHandleAt(0);804Oop oop = objectHeap.newOop(oopHandle);805// exclude JNI handles hotspot internal objects806if (oop != null && isJavaVisible(oop)) {807out.writeByte((byte) HPROF_GC_ROOT_JNI_LOCAL);808writeObjectID(oop);809out.writeInt(threadIndex);810out.writeInt(EMPTY_FRAME_DEPTH);811}812}813} catch (IOException exp) {814throw new RuntimeException(exp);815}816}817public void visitCompOopAddress(Address handleAddr) {818throw new RuntimeException(819" Should not reach here. JNIHandles are not compressed \n");820}821});822} catch (RuntimeException re) {823handleRuntimeException(re);824}825}826}827828protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {829OopHandle oopHandle = handleAddr.getOopHandleAt(0);830Oop oop = objectHeap.newOop(oopHandle);831// exclude JNI handles of hotspot internal objects832if (oop != null && isJavaVisible(oop)) {833out.writeByte((byte) HPROF_GC_ROOT_JNI_GLOBAL);834writeObjectID(oop);835// use JNIHandle address as ID836writeObjectID(getAddressValue(handleAddr));837}838}839840protected void writeObjectArray(ObjArray array) throws IOException {841int headerSize = getArrayHeaderSize(true);842final int length = calculateArrayMaxLength(array.getLength(),843headerSize,844OBJ_ID_SIZE,845"Object");846out.writeByte((byte) HPROF_GC_OBJ_ARRAY_DUMP);847writeObjectID(array);848out.writeInt(DUMMY_STACK_TRACE_ID);849out.writeInt(length);850writeObjectID(array.getKlass().getJavaMirror());851for (int index = 0; index < length; index++) {852OopHandle handle = array.getOopHandleAt(index);853writeObjectID(getAddressValue(handle));854}855}856857protected void writePrimitiveArray(TypeArray array) throws IOException {858int headerSize = getArrayHeaderSize(false);859TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();860final int type = (int) tak.getElementType();861final String typeName = tak.getElementTypeName();862final long typeSize = getSizeForType(type);863final int length = calculateArrayMaxLength(array.getLength(),864headerSize,865typeSize,866typeName);867out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP);868writeObjectID(array);869out.writeInt(DUMMY_STACK_TRACE_ID);870out.writeInt(length);871out.writeByte((byte) type);872switch (type) {873case TypeArrayKlass.T_BOOLEAN:874writeBooleanArray(array, length);875break;876case TypeArrayKlass.T_CHAR:877writeCharArray(array, length);878break;879case TypeArrayKlass.T_FLOAT:880writeFloatArray(array, length);881break;882case TypeArrayKlass.T_DOUBLE:883writeDoubleArray(array, length);884break;885case TypeArrayKlass.T_BYTE:886writeByteArray(array, length);887break;888case TypeArrayKlass.T_SHORT:889writeShortArray(array, length);890break;891case TypeArrayKlass.T_INT:892writeIntArray(array, length);893break;894case TypeArrayKlass.T_LONG:895writeLongArray(array, length);896break;897default:898throw new RuntimeException(899"Should not reach here: Unknown type: " + type);900}901}902903private void writeBooleanArray(TypeArray array, int length) throws IOException {904for (int index = 0; index < length; index++) {905long offset = BOOLEAN_BASE_OFFSET + index * BOOLEAN_SIZE;906out.writeBoolean(array.getHandle().getJBooleanAt(offset));907}908}909910private void writeByteArray(TypeArray array, int length) throws IOException {911for (int index = 0; index < length; index++) {912long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;913out.writeByte(array.getHandle().getJByteAt(offset));914}915}916917private void writeShortArray(TypeArray array, int length) throws IOException {918for (int index = 0; index < length; index++) {919long offset = SHORT_BASE_OFFSET + index * SHORT_SIZE;920out.writeShort(array.getHandle().getJShortAt(offset));921}922}923924private void writeIntArray(TypeArray array, int length) throws IOException {925for (int index = 0; index < length; index++) {926long offset = INT_BASE_OFFSET + index * INT_SIZE;927out.writeInt(array.getHandle().getJIntAt(offset));928}929}930931private void writeLongArray(TypeArray array, int length) throws IOException {932for (int index = 0; index < length; index++) {933long offset = LONG_BASE_OFFSET + index * LONG_SIZE;934out.writeLong(array.getHandle().getJLongAt(offset));935}936}937938private void writeCharArray(TypeArray array, int length) throws IOException {939for (int index = 0; index < length; index++) {940long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;941out.writeChar(array.getHandle().getJCharAt(offset));942}943}944945private void writeFloatArray(TypeArray array, int length) throws IOException {946for (int index = 0; index < length; index++) {947long offset = FLOAT_BASE_OFFSET + index * FLOAT_SIZE;948out.writeFloat(array.getHandle().getJFloatAt(offset));949}950}951952private void writeDoubleArray(TypeArray array, int length) throws IOException {953for (int index = 0; index < length; index++) {954long offset = DOUBLE_BASE_OFFSET + index * DOUBLE_SIZE;955out.writeDouble(array.getHandle().getJDoubleAt(offset));956}957}958959protected void writeInstance(Instance instance) throws IOException {960Klass klass = instance.getKlass();961if (klass.getClassLoaderData() == null) {962// Ignoring this object since the corresponding Klass is not loaded.963// Might be a dormant archive object.964return;965}966967out.writeByte((byte) HPROF_GC_INSTANCE_DUMP);968writeObjectID(instance);969out.writeInt(DUMMY_STACK_TRACE_ID);970writeObjectID(klass.getJavaMirror());971972ClassData cd = (ClassData) classDataCache.get(klass);973974if (Assert.ASSERTS_ENABLED) {975Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getAddress());976}977List<Field> fields = cd.fields;978int size = cd.instSize;979out.writeInt(size);980for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {981writeField(itr.next(), instance);982}983}984985//-- Internals only below this point986987private void writeFieldDescriptors(List<Field> fields, InstanceKlass ik)988throws IOException {989// ik == null for instance fields.990out.writeShort((short) fields.size());991for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {992Field field = itr.next();993Symbol name = field.getName();994writeSymbolID(name);995char typeCode = (char) field.getSignature().getByteAt(0);996int kind = signatureToHprofKind(typeCode);997out.writeByte((byte)kind);998if (ik != null) {999// static field1000writeField(field, ik.getJavaMirror());1001}1002}1003}10041005public static int signatureToHprofKind(char ch) {1006switch (ch) {1007case JVM_SIGNATURE_CLASS:1008case JVM_SIGNATURE_ARRAY:1009return HPROF_NORMAL_OBJECT;1010case JVM_SIGNATURE_BOOLEAN:1011return HPROF_BOOLEAN;1012case JVM_SIGNATURE_CHAR:1013return HPROF_CHAR;1014case JVM_SIGNATURE_FLOAT:1015return HPROF_FLOAT;1016case JVM_SIGNATURE_DOUBLE:1017return HPROF_DOUBLE;1018case JVM_SIGNATURE_BYTE:1019return HPROF_BYTE;1020case JVM_SIGNATURE_SHORT:1021return HPROF_SHORT;1022case JVM_SIGNATURE_INT:1023return HPROF_INT;1024case JVM_SIGNATURE_LONG:1025return HPROF_LONG;1026default:1027throw new RuntimeException("should not reach here");1028}1029}10301031private void writeField(Field field, Oop oop) throws IOException {1032char typeCode = (char) field.getSignature().getByteAt(0);1033switch (typeCode) {1034case JVM_SIGNATURE_BOOLEAN:1035out.writeBoolean(((BooleanField)field).getValue(oop));1036break;1037case JVM_SIGNATURE_CHAR:1038out.writeChar(((CharField)field).getValue(oop));1039break;1040case JVM_SIGNATURE_BYTE:1041out.writeByte(((ByteField)field).getValue(oop));1042break;1043case JVM_SIGNATURE_SHORT:1044out.writeShort(((ShortField)field).getValue(oop));1045break;1046case JVM_SIGNATURE_INT:1047out.writeInt(((IntField)field).getValue(oop));1048break;1049case JVM_SIGNATURE_LONG:1050out.writeLong(((LongField)field).getValue(oop));1051break;1052case JVM_SIGNATURE_FLOAT:1053out.writeFloat(((FloatField)field).getValue(oop));1054break;1055case JVM_SIGNATURE_DOUBLE:1056out.writeDouble(((DoubleField)field).getValue(oop));1057break;1058case JVM_SIGNATURE_CLASS:1059case JVM_SIGNATURE_ARRAY: {1060if (VM.getVM().isCompressedOopsEnabled()) {1061OopHandle handle = ((NarrowOopField)field).getValueAsOopHandle(oop);1062writeObjectID(getAddressValue(handle));1063} else {1064OopHandle handle = ((OopField)field).getValueAsOopHandle(oop);1065writeObjectID(getAddressValue(handle));1066}1067break;1068}1069default:1070throw new RuntimeException("should not reach here");1071}1072}10731074private void writeHeader(int tag, int len) throws IOException {1075out.writeByte((byte)tag);1076out.writeInt(0); // current ticks1077out.writeInt(len);1078}10791080private void writeDummyTrace() throws IOException {1081writeHeader(HPROF_TRACE, 3 * 4);1082out.writeInt(DUMMY_STACK_TRACE_ID);1083out.writeInt(0);1084out.writeInt(0);1085}10861087private void writeClassSymbols(Klass k) throws IOException {1088writeSymbol(k.getName());1089if (k instanceof InstanceKlass) {1090InstanceKlass ik = (InstanceKlass) k;1091List<Field> declaredFields = ik.getImmediateFields();1092for (Iterator<Field> itr = declaredFields.iterator(); itr.hasNext();) {1093Field field = itr.next();1094writeSymbol(field.getName());1095}1096}1097}10981099private void writeSymbols() throws IOException {1100// Write all the symbols that are used by the classes1101ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();1102try {1103cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {1104public void visit(Klass k) {1105try {1106writeClassSymbols(k);1107} catch (IOException e) {1108throw new RuntimeException(e);1109}1110}1111});1112} catch (RuntimeException re) {1113handleRuntimeException(re);1114}1115}11161117private void writeSymbol(Symbol sym) throws IOException {1118// If name is already written don't write it again.1119if (names.add(sym)) {1120if(sym != null) {1121byte[] buf = sym.asString().getBytes("UTF-8");1122writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE);1123writeSymbolID(sym);1124out.write(buf);1125} else {1126writeHeader(HPROF_UTF8, 0 + OBJ_ID_SIZE);1127writeSymbolID(null);1128}1129}1130}11311132private void writeClasses() throws IOException {1133// write class list (id, name) association1134ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();1135try {1136cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {1137public void visit(Klass k) {1138try {1139Instance clazz = k.getJavaMirror();1140writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));1141out.writeInt(serialNum);1142writeObjectID(clazz);1143KlassMap.add(serialNum - 1, k);1144out.writeInt(DUMMY_STACK_TRACE_ID);1145writeSymbolID(k.getName());1146serialNum++;1147} catch (IOException exp) {1148throw new RuntimeException(exp);1149}1150}1151});1152} catch (RuntimeException re) {1153handleRuntimeException(re);1154}1155}11561157// writes hprof binary file header1158private void writeFileHeader() throws IOException {1159// version string1160out.writeBytes(HPROF_HEADER_1_0_2);1161out.writeByte((byte)'\0');11621163// write identifier size. we use pointers as identifiers.1164out.writeInt(OBJ_ID_SIZE);11651166// timestamp -- file creation time.1167out.writeLong(System.currentTimeMillis());1168}11691170// writes unique ID for an object1171private void writeObjectID(Oop oop) throws IOException {1172OopHandle handle = (oop != null)? oop.getHandle() : null;1173long address = getAddressValue(handle);1174writeObjectID(address);1175}11761177private void writeSymbolID(Symbol sym) throws IOException {1178assert names.contains(sym);1179long address = (sym != null) ? getAddressValue(sym.getAddress()) : getAddressValue(null);1180writeObjectID(address);1181}11821183private void writeObjectID(long address) throws IOException {1184if (OBJ_ID_SIZE == 4) {1185out.writeInt((int) address);1186} else {1187out.writeLong(address);1188}1189}11901191private long getAddressValue(Address addr) {1192return (addr == null)? 0L : dbg.getAddressValue(addr);1193}11941195// get all declared as well as inherited (directly/indirectly) fields1196private static List<Field> getInstanceFields(InstanceKlass ik) {1197InstanceKlass klass = ik;1198List<Field> res = new ArrayList<>();1199while (klass != null) {1200List<Field> curFields = klass.getImmediateFields();1201for (Iterator<Field> itr = curFields.iterator(); itr.hasNext();) {1202Field f = itr.next();1203if (! f.isStatic()) {1204res.add(f);1205}1206}1207klass = (InstanceKlass) klass.getSuper();1208}1209return res;1210}12111212// get size in bytes (in stream) required for given fields. Note1213// that this is not the same as object size in heap. The size in1214// heap will include size of padding/alignment bytes as well.1215private int getSizeForFields(List<Field> fields) {1216int size = 0;1217for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {1218Field field = itr.next();1219char typeCode = (char) field.getSignature().getByteAt(0);1220switch (typeCode) {1221case JVM_SIGNATURE_BOOLEAN:1222case JVM_SIGNATURE_BYTE:1223size++;1224break;1225case JVM_SIGNATURE_CHAR:1226case JVM_SIGNATURE_SHORT:1227size += 2;1228break;1229case JVM_SIGNATURE_INT:1230case JVM_SIGNATURE_FLOAT:1231size += 4;1232break;1233case JVM_SIGNATURE_CLASS:1234case JVM_SIGNATURE_ARRAY:1235size += OBJ_ID_SIZE;1236break;1237case JVM_SIGNATURE_LONG:1238case JVM_SIGNATURE_DOUBLE:1239size += 8;1240break;1241default:1242throw new RuntimeException("should not reach here");1243}1244}1245return size;1246}12471248private boolean isCompression() {1249return (gzLevel >= 1 && gzLevel <= 9);1250}12511252// Convert integer to byte array with BIG_ENDIAN byte order.1253private static byte[] genByteArrayFromInt(int value) {1254ByteBuffer intBuffer = ByteBuffer.allocate(4);1255intBuffer.order(ByteOrder.BIG_ENDIAN);1256intBuffer.putInt(value);1257return intBuffer.array();1258}12591260// We don't have allocation site info. We write a dummy1261// stack trace with this id.1262private static final int DUMMY_STACK_TRACE_ID = 1;1263private static final int EMPTY_FRAME_DEPTH = -1;12641265private DataOutputStream out;1266private FileOutputStream fos;1267private SegmentedOutputStream hprofBufferedOut;1268private Debugger dbg;1269private ObjectHeap objectHeap;1270private ArrayList<Klass> KlassMap;1271private int gzLevel;12721273// oopSize of the debuggee1274private int OBJ_ID_SIZE;12751276// Added for hprof file format 1.0.2 support1277private boolean useSegmentedHeapDump;1278private long currentSegmentStart;12791280private long BOOLEAN_BASE_OFFSET;1281private long BYTE_BASE_OFFSET;1282private long CHAR_BASE_OFFSET;1283private long SHORT_BASE_OFFSET;1284private long INT_BASE_OFFSET;1285private long LONG_BASE_OFFSET;1286private long FLOAT_BASE_OFFSET;1287private long DOUBLE_BASE_OFFSET;1288private long OBJECT_BASE_OFFSET;12891290private long BOOLEAN_SIZE;1291private long BYTE_SIZE;1292private long CHAR_SIZE;1293private long SHORT_SIZE;1294private long INT_SIZE;1295private long LONG_SIZE;1296private long FLOAT_SIZE;1297private long DOUBLE_SIZE;12981299private static class ClassData {1300int instSize;1301List<Field> fields;13021303ClassData(int instSize, List<Field> fields) {1304this.instSize = instSize;1305this.fields = fields;1306}1307}13081309private Map<InstanceKlass, ClassData> classDataCache = new HashMap<>();13101311/**1312* The class implements a buffered output stream for segmented data dump.1313* It is used inside HeapHprofBinWritter only for heap dump.1314* Because the current implementation of segmented heap dump needs to update1315* the segment size at segment header, and because it is hard to modify the1316* compressed data after they are written to file, this class first saves the1317* uncompressed data into an internal buffer, and then writes through to the1318* GZIPOutputStream when the whole segmented data are ready and the size is updated.1319* If the data to be written are larger than internal buffer, or the internal buffer1320* is full, the internal buffer will be extend to a larger one.1321* This class defines a switch to turn on/off the segmented mode. If turned off,1322* it behaves the same as BufferedOutputStream.1323* */1324private class SegmentedOutputStream extends BufferedOutputStream {1325/**1326* Creates a new buffered output stream to support segmented heap dump data.1327*1328* @param out the underlying output stream.1329* @param allowSegmented whether allow segmental dump.1330*/1331public SegmentedOutputStream(OutputStream out, boolean allowSegmented) {1332super(out, 8192);1333segmentMode = false;1334this.allowSegmented = allowSegmented;1335segmentBuffer = new byte[SEGMENT_BUFFER_SIZE];1336segmentWritten = 0;1337}13381339/**1340* Creates a new buffered output stream to support segmented heap dump data.1341*1342* @param out the underlying output stream.1343*/1344public SegmentedOutputStream(OutputStream out) {1345this(out, true);1346}13471348/**1349* Writes the specified byte to this buffered output stream.1350*1351* @param b the byte to be written.1352* @throws IOException if an I/O error occurs.1353*/1354@Override1355public synchronized void write(int b) throws IOException {1356if (segmentMode) {1357if (segmentWritten == 0) {1358// At the begining of the segment.1359writeSegmentHeader();1360} else if (segmentWritten == segmentBuffer.length) {1361// Internal buffer is full, extend a larger one.1362int newSize = segmentBuffer.length + SEGMENT_BUFFER_INC_SIZE;1363byte newBuf[] = new byte[newSize];1364System.arraycopy(segmentBuffer, 0, newBuf, 0, segmentWritten);1365segmentBuffer = newBuf;1366}1367segmentBuffer[segmentWritten++] = (byte)b;1368return;1369}1370super.write(b);1371}13721373/**1374* Writes {@code len} bytes from the specified byte array1375* starting at offset {@code off} to this output stream.1376*1377* @param b the data.1378* @param off the start offset in the data.1379* @param len the number of bytes to write.1380* @throws IOException if an I/O error occurs.1381*/1382@Override1383public synchronized void write(byte b[], int off, int len) throws IOException {1384if (segmentMode) {1385if (segmentWritten == 0) {1386writeSegmentHeader();1387}1388// Data size is larger than segment buffer length, extend segment buffer.1389if (segmentWritten + len > segmentBuffer.length) {1390int newSize = segmentBuffer.length + Math.max(SEGMENT_BUFFER_INC_SIZE, len);1391byte newBuf[] = new byte[newSize];1392System.arraycopy(segmentBuffer, 0, newBuf, 0, segmentWritten);1393segmentBuffer = newBuf;1394}1395System.arraycopy(b, off, segmentBuffer, segmentWritten, len);1396segmentWritten += len;1397return;1398}1399super.write(b, off, len);1400}14011402/**1403* Flushes this buffered output stream. This forces any buffered1404* output bytes to be written out to the underlying output stream.1405*1406* @throws IOException if an I/O error occurs.1407* @see java.io.FilterOutputStream#out1408*/1409@Override1410public synchronized void flush() throws IOException {1411if (segmentMode) {1412// The case that nothing has been written in segment.1413if (segmentWritten == 0) return;1414// There must be more data than just header size written for non-empty segment.1415assert segmentWritten > SEGMENT_HEADER_SIZE1416: "invalid header in segmented mode";14171418if (segmentWritten > (segmentBuffer.length)) {1419throw new RuntimeException("Heap segment size overflow.");1420}14211422if (segmentWritten > SEGMENT_HEADER_SIZE) {1423fillSegmentSize(segmentWritten - SEGMENT_HEADER_SIZE);1424super.write(segmentBuffer, 0, segmentWritten);1425super.flush();1426segmentWritten = 0;1427}1428return;1429}1430super.flush();1431}14321433/**1434* Enters segmented mode, flush buffered data and set flag.1435*/1436public void enterSegmentMode() throws IOException {1437if (allowSegmented && !segmentMode && segmentWritten == 0) {1438super.flush();1439segmentMode = true;1440segmentWritten = 0;1441}1442}14431444/**1445* Before finish, flush all data in buffer.1446*/1447public void finish() throws IOException {1448if (allowSegmented && segmentMode) {1449flush();1450assert segmentWritten == 0;1451segmentMode = false;1452}1453}14541455/**1456* Exits segmented mode, flush segmented data.1457* @param force flush data regardless whether the buffer is full1458*/1459public void exitSegmentMode() throws IOException {1460if (allowSegmented && segmentMode && shouldFlush()) {1461flush();1462assert segmentWritten == 0;1463segmentMode = false;1464}1465}146614671468/**1469* Check whether the data should be flush based on data saved in1470* segmentBuffer.1471* This method is used to control the segments number and the memory usage.1472* If segment is too small, there will be lots segments in final dump file.1473* If it is too large, lots of memory is used in RAM.1474*/1475private boolean shouldFlush() {1476// return true if data in segmentBuffer has been extended.1477return segmentWritten > SEGMENT_BUFFER_SIZE;1478}14791480/**1481* Writes the write segment header into internal buffer.1482*/1483private void writeSegmentHeader() {1484assert segmentWritten == 0;1485segmentBuffer[segmentWritten++] = (byte)HPROF_HEAP_DUMP_SEGMENT;1486writeInteger(0);1487// segment size, write dummy length of 0 and we'll fix it later.1488writeInteger(0);1489}14901491/**1492* Fills the segmented data size into the header.1493*/1494private void fillSegmentSize(int size) {1495byte[] lenBytes = genByteArrayFromInt(size);1496System.arraycopy(lenBytes, 0, segmentBuffer, 5, 4);1497}14981499/**1500* Writes an {@code int} to the internal segment buffer1501* {@code written} is incremented by {@code 4}.1502*/1503private final void writeInteger(int value) {1504byte[] intBytes = genByteArrayFromInt(value);1505System.arraycopy(intBytes, 0, segmentBuffer, segmentWritten, 4);1506segmentWritten += 4;1507}15081509// The buffer size for segmentBuffer.1510// Since it is hard to calculate and fill the data size of an segment in compressed1511// data, making the segmented data stored in this buffer could help rewrite the data1512// size before the segmented data are written to underlying GZIPOutputStream.1513private static final int SEGMENT_BUFFER_SIZE = 1 << 20;1514// Buffer size used to extend the segment buffer.1515private static final int SEGMENT_BUFFER_INC_SIZE = 1 << 10;1516// Headers:1517// 1 byte for HPROF_HEAP_DUMP_SEGMENT1518// 4 bytes for timestamp1519// 4 bytes for size1520private static final int SEGMENT_HEADER_SIZE = 9;1521// Segment support.1522private boolean segmentMode;1523private boolean allowSegmented;1524private byte segmentBuffer[];1525private int segmentWritten;1526}1527}152815291530