Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
41161 views
1
/*
2
* Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
package sun.jvm.hotspot.utilities;
26
27
import java.io.*;
28
import java.nio.ByteBuffer;
29
import java.nio.ByteOrder;
30
import java.nio.channels.*;
31
import java.util.*;
32
import java.util.zip.*;
33
import sun.jvm.hotspot.debugger.*;
34
import sun.jvm.hotspot.memory.*;
35
import sun.jvm.hotspot.oops.*;
36
import sun.jvm.hotspot.runtime.*;
37
import sun.jvm.hotspot.classfile.*;
38
import sun.jvm.hotspot.gc.z.ZCollectedHeap;
39
40
/*
41
* This class writes Java heap in hprof binary format. This format is
42
* used by Heap Analysis Tool (HAT). The class is heavily influenced
43
* by 'hprof_io.c' of 1.5 new hprof implementation.
44
*/
45
46
/* hprof binary format: (result either written to a file or sent over
47
* the network).
48
*
49
* WARNING: This format is still under development, and is subject to
50
* change without notice.
51
*
52
* header "JAVA PROFILE 1.0.2" (0-terminated)
53
* u4 size of identifiers. Identifiers are used to represent
54
* UTF8 strings, objects, stack traces, etc. They usually
55
* have the same size as host pointers. For example, on
56
* Solaris and Win32, the size is 4.
57
* u4 high word
58
* u4 low word number of milliseconds since 0:00 GMT, 1/1/70
59
* [record]* a sequence of records.
60
*
61
*/
62
63
/*
64
*
65
* Record format:
66
*
67
* u1 a TAG denoting the type of the record
68
* u4 number of *microseconds* since the time stamp in the
69
* header. (wraps around in a little more than an hour)
70
* u4 number of bytes *remaining* in the record. Note that
71
* this number excludes the tag and the length field itself.
72
* [u1]* BODY of the record (a sequence of bytes)
73
*/
74
75
/*
76
* The following TAGs are supported:
77
*
78
* TAG BODY notes
79
*----------------------------------------------------------
80
* HPROF_UTF8 a UTF8-encoded name
81
*
82
* id name ID
83
* [u1]* UTF8 characters (no trailing zero)
84
*
85
* HPROF_LOAD_CLASS a newly loaded class
86
*
87
* u4 class serial number (> 0)
88
* id class object ID
89
* u4 stack trace serial number
90
* id class name ID
91
*
92
* HPROF_UNLOAD_CLASS an unloading class
93
*
94
* u4 class serial_number
95
*
96
* HPROF_FRAME a Java stack frame
97
*
98
* id stack frame ID
99
* id method name ID
100
* id method signature ID
101
* id source file name ID
102
* u4 class serial number
103
* i4 line number. >0: normal
104
* -1: unknown
105
* -2: compiled method
106
* -3: native method
107
*
108
* HPROF_TRACE a Java stack trace
109
*
110
* u4 stack trace serial number
111
* u4 thread serial number
112
* u4 number of frames
113
* [id]* stack frame IDs
114
*
115
*
116
* HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC
117
*
118
* u2 flags 0x0001: incremental vs. complete
119
* 0x0002: sorted by allocation vs. live
120
* 0x0004: whether to force a GC
121
* u4 cutoff ratio
122
* u4 total live bytes
123
* u4 total live instances
124
* u8 total bytes allocated
125
* u8 total instances allocated
126
* u4 number of sites that follow
127
* [u1 is_array: 0: normal object
128
* 2: object array
129
* 4: boolean array
130
* 5: char array
131
* 6: float array
132
* 7: double array
133
* 8: byte array
134
* 9: short array
135
* 10: int array
136
* 11: long array
137
* u4 class serial number (may be zero during startup)
138
* u4 stack trace serial number
139
* u4 number of bytes alive
140
* u4 number of instances alive
141
* u4 number of bytes allocated
142
* u4]* number of instance allocated
143
*
144
* HPROF_START_THREAD a newly started thread.
145
*
146
* u4 thread serial number (> 0)
147
* id thread object ID
148
* u4 stack trace serial number
149
* id thread name ID
150
* id thread group name ID
151
* id thread group parent name ID
152
*
153
* HPROF_END_THREAD a terminating thread.
154
*
155
* u4 thread serial number
156
*
157
* HPROF_HEAP_SUMMARY heap summary
158
*
159
* u4 total live bytes
160
* u4 total live instances
161
* u8 total bytes allocated
162
* u8 total instances allocated
163
*
164
* HPROF_HEAP_DUMP denote a heap dump
165
*
166
* [heap dump sub-records]*
167
*
168
* There are four kinds of heap dump sub-records:
169
*
170
* u1 sub-record type
171
*
172
* HPROF_GC_ROOT_UNKNOWN unknown root
173
*
174
* id object ID
175
*
176
* HPROF_GC_ROOT_THREAD_OBJ thread object
177
*
178
* id thread object ID (may be 0 for a
179
* thread newly attached through JNI)
180
* u4 thread sequence number
181
* u4 stack trace sequence number
182
*
183
* HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root
184
*
185
* id object ID
186
* id JNI global ref ID
187
*
188
* HPROF_GC_ROOT_JNI_LOCAL JNI local ref
189
*
190
* id object ID
191
* u4 thread serial number
192
* u4 frame # in stack trace (-1 for empty)
193
*
194
* HPROF_GC_ROOT_JAVA_FRAME Java stack frame
195
*
196
* id object ID
197
* u4 thread serial number
198
* u4 frame # in stack trace (-1 for empty)
199
*
200
* HPROF_GC_ROOT_NATIVE_STACK Native stack
201
*
202
* id object ID
203
* u4 thread serial number
204
*
205
* HPROF_GC_ROOT_STICKY_CLASS System class
206
*
207
* id object ID
208
*
209
* HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block
210
*
211
* id object ID
212
* u4 thread serial number
213
*
214
* HPROF_GC_ROOT_MONITOR_USED Busy monitor
215
*
216
* id object ID
217
*
218
* HPROF_GC_CLASS_DUMP dump of a class object
219
*
220
* id class object ID
221
* u4 stack trace serial number
222
* id super class object ID
223
* id class loader object ID
224
* id signers object ID
225
* id protection domain object ID
226
* id reserved
227
* id reserved
228
*
229
* u4 instance size (in bytes)
230
*
231
* u2 size of constant pool
232
* [u2, constant pool index,
233
* ty, type
234
* 2: object
235
* 4: boolean
236
* 5: char
237
* 6: float
238
* 7: double
239
* 8: byte
240
* 9: short
241
* 10: int
242
* 11: long
243
* vl]* and value
244
*
245
* u2 number of static fields
246
* [id, static field name,
247
* ty, type,
248
* vl]* and value
249
*
250
* u2 number of inst. fields (not inc. super)
251
* [id, instance field name,
252
* ty]* type
253
*
254
* HPROF_GC_INSTANCE_DUMP dump of a normal object
255
*
256
* id object ID
257
* u4 stack trace serial number
258
* id class object ID
259
* u4 number of bytes that follow
260
* [vl]* instance field values (class, followed
261
* by super, super's super ...)
262
*
263
* HPROF_GC_OBJ_ARRAY_DUMP dump of an object array
264
*
265
* id array object ID
266
* u4 stack trace serial number
267
* u4 number of elements
268
* id array class ID
269
* [id]* elements
270
*
271
* HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array
272
*
273
* id array object ID
274
* u4 stack trace serial number
275
* u4 number of elements
276
* u1 element type
277
* 4: boolean array
278
* 5: char array
279
* 6: float array
280
* 7: double array
281
* 8: byte array
282
* 9: short array
283
* 10: int array
284
* 11: long array
285
* [u1]* elements
286
*
287
* HPROF_CPU_SAMPLES a set of sample traces of running threads
288
*
289
* u4 total number of samples
290
* u4 # of traces
291
* [u4 # of samples
292
* u4]* stack trace serial number
293
*
294
* HPROF_CONTROL_SETTINGS the settings of on/off switches
295
*
296
* u4 0x00000001: alloc traces on/off
297
* 0x00000002: cpu sampling on/off
298
* u2 stack trace depth
299
*
300
*
301
* A heap dump can optionally be generated as a sequence of heap dump
302
* segments. This sequence is terminated by an end record. The additional
303
* tags allowed by format "JAVA PROFILE 1.0.2" are:
304
*
305
* HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment
306
*
307
* [heap dump sub-records]*
308
* The same sub-record types allowed by HPROF_HEAP_DUMP
309
*
310
* HPROF_HEAP_DUMP_END denotes the end of a heap dump
311
*
312
*/
313
314
public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
315
316
// Record which Symbol names have been dumped already.
317
private HashSet<Symbol> names;
318
319
private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000;
320
321
// The approximate size of a heap segment. Used to calculate when to create
322
// a new segment.
323
private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000;
324
325
// hprof binary file header
326
private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2";
327
328
// constants in enum HprofTag
329
private static final int HPROF_UTF8 = 0x01;
330
private static final int HPROF_LOAD_CLASS = 0x02;
331
private static final int HPROF_UNLOAD_CLASS = 0x03;
332
private static final int HPROF_FRAME = 0x04;
333
private static final int HPROF_TRACE = 0x05;
334
private static final int HPROF_ALLOC_SITES = 0x06;
335
private static final int HPROF_HEAP_SUMMARY = 0x07;
336
private static final int HPROF_START_THREAD = 0x0A;
337
private static final int HPROF_END_THREAD = 0x0B;
338
private static final int HPROF_HEAP_DUMP = 0x0C;
339
private static final int HPROF_CPU_SAMPLES = 0x0D;
340
private static final int HPROF_CONTROL_SETTINGS = 0x0E;
341
342
// 1.0.2 record types
343
private static final int HPROF_HEAP_DUMP_SEGMENT = 0x1C;
344
private static final int HPROF_HEAP_DUMP_END = 0x2C;
345
346
// Heap dump constants
347
// constants in enum HprofGcTag
348
private static final int HPROF_GC_ROOT_UNKNOWN = 0xFF;
349
private static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01;
350
private static final int HPROF_GC_ROOT_JNI_LOCAL = 0x02;
351
private static final int HPROF_GC_ROOT_JAVA_FRAME = 0x03;
352
private static final int HPROF_GC_ROOT_NATIVE_STACK = 0x04;
353
private static final int HPROF_GC_ROOT_STICKY_CLASS = 0x05;
354
private static final int HPROF_GC_ROOT_THREAD_BLOCK = 0x06;
355
private static final int HPROF_GC_ROOT_MONITOR_USED = 0x07;
356
private static final int HPROF_GC_ROOT_THREAD_OBJ = 0x08;
357
private static final int HPROF_GC_CLASS_DUMP = 0x20;
358
private static final int HPROF_GC_INSTANCE_DUMP = 0x21;
359
private static final int HPROF_GC_OBJ_ARRAY_DUMP = 0x22;
360
private static final int HPROF_GC_PRIM_ARRAY_DUMP = 0x23;
361
362
// constants in enum HprofType
363
private static final int HPROF_ARRAY_OBJECT = 1;
364
private static final int HPROF_NORMAL_OBJECT = 2;
365
private static final int HPROF_BOOLEAN = 4;
366
private static final int HPROF_CHAR = 5;
367
private static final int HPROF_FLOAT = 6;
368
private static final int HPROF_DOUBLE = 7;
369
private static final int HPROF_BYTE = 8;
370
private static final int HPROF_SHORT = 9;
371
private static final int HPROF_INT = 10;
372
private static final int HPROF_LONG = 11;
373
374
// Java type codes
375
private static final int JVM_SIGNATURE_BOOLEAN = 'Z';
376
private static final int JVM_SIGNATURE_CHAR = 'C';
377
private static final int JVM_SIGNATURE_BYTE = 'B';
378
private static final int JVM_SIGNATURE_SHORT = 'S';
379
private static final int JVM_SIGNATURE_INT = 'I';
380
private static final int JVM_SIGNATURE_LONG = 'J';
381
private static final int JVM_SIGNATURE_FLOAT = 'F';
382
private static final int JVM_SIGNATURE_DOUBLE = 'D';
383
private static final int JVM_SIGNATURE_ARRAY = '[';
384
private static final int JVM_SIGNATURE_CLASS = 'L';
385
386
private static final long MAX_U4_VALUE = 0xFFFFFFFFL;
387
int serialNum = 1;
388
389
public HeapHprofBinWriter() {
390
this.KlassMap = new ArrayList<Klass>();
391
this.names = new HashSet<Symbol>();
392
this.gzLevel = 0;
393
}
394
395
public HeapHprofBinWriter(int gzLevel) {
396
this.KlassMap = new ArrayList<Klass>();
397
this.names = new HashSet<Symbol>();
398
this.gzLevel = gzLevel;
399
}
400
401
public synchronized void write(String fileName) throws IOException {
402
VM vm = VM.getVM();
403
404
// Check whether we should dump the heap as segments
405
useSegmentedHeapDump = isCompression() ||
406
(vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD);
407
408
// open file stream and create buffered data output stream
409
fos = new FileOutputStream(fileName);
410
hprofBufferedOut = null;
411
OutputStream dataOut = fos;
412
if (useSegmentedHeapDump) {
413
if (isCompression()) {
414
dataOut = new GZIPOutputStream(fos) {
415
{
416
this.def.setLevel(gzLevel);
417
}
418
};
419
}
420
hprofBufferedOut = new SegmentedOutputStream(dataOut);
421
} else {
422
hprofBufferedOut = new SegmentedOutputStream(fos, false /* allowSegmented */);
423
}
424
out = new DataOutputStream(hprofBufferedOut);
425
dbg = vm.getDebugger();
426
objectHeap = vm.getObjectHeap();
427
428
OBJ_ID_SIZE = (int) vm.getOopSize();
429
430
BOOLEAN_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BOOLEAN);
431
BYTE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BYTE);
432
CHAR_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_CHAR);
433
SHORT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_SHORT);
434
INT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_INT);
435
LONG_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_LONG);
436
FLOAT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_FLOAT);
437
DOUBLE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_DOUBLE);
438
OBJECT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_OBJECT);
439
440
BOOLEAN_SIZE = objectHeap.getBooleanSize();
441
BYTE_SIZE = objectHeap.getByteSize();
442
CHAR_SIZE = objectHeap.getCharSize();
443
SHORT_SIZE = objectHeap.getShortSize();
444
INT_SIZE = objectHeap.getIntSize();
445
LONG_SIZE = objectHeap.getLongSize();
446
FLOAT_SIZE = objectHeap.getFloatSize();
447
DOUBLE_SIZE = objectHeap.getDoubleSize();
448
449
// hprof bin format header
450
writeFileHeader();
451
452
// dummy stack trace without any frames so that
453
// HAT can be run without -stack false option
454
writeDummyTrace();
455
456
// hprof UTF-8 symbols section
457
writeSymbols();
458
459
// HPROF_LOAD_CLASS records for all classes
460
writeClasses();
461
462
// write HPROF_FRAME and HPROF_TRACE records
463
dumpStackTraces();
464
465
// write CLASS_DUMP records
466
writeClassDumpRecords();
467
468
// this will write heap data into the buffer stream
469
super.write();
470
471
// flush buffer stream.
472
out.flush();
473
474
if (!useSegmentedHeapDump) {
475
// Fill in final length.
476
fillInHeapRecordLength();
477
} else {
478
hprofBufferedOut.finish();
479
// Write heap segment-end record
480
out.writeByte((byte) HPROF_HEAP_DUMP_END);
481
out.writeInt(0);
482
out.writeInt(0);
483
}
484
485
// flush buffer stream and throw it.
486
out.flush();
487
out.close();
488
out = null;
489
hprofBufferedOut = null;
490
}
491
492
@Override
493
protected void writeHeapRecordPrologue() throws IOException {
494
if (useSegmentedHeapDump) {
495
hprofBufferedOut.enterSegmentMode();
496
} else if (currentSegmentStart == 0) {
497
// write heap data header
498
out.writeByte((byte) (HPROF_HEAP_DUMP));
499
out.writeInt(0);
500
501
// remember position of dump length, we will fixup
502
// length later - hprof format requires length.
503
out.flush();
504
currentSegmentStart = fos.getChannel().position();
505
// write dummy length of 0 and we'll fix it later.
506
out.writeInt(0);
507
}
508
}
509
510
@Override
511
protected void writeHeapRecordEpilogue() throws IOException {
512
if (useSegmentedHeapDump) {
513
hprofBufferedOut.exitSegmentMode();
514
}
515
}
516
517
private void fillInHeapRecordLength() throws IOException {
518
assert !useSegmentedHeapDump : "fillInHeapRecordLength is not supported for segmented heap dump";
519
520
// now get the current position to calculate length
521
long dumpEnd = fos.getChannel().position();
522
523
// calculate the length of heap data
524
long dumpLenLong = (dumpEnd - currentSegmentStart - 4L);
525
526
// Check length boundary, overflow could happen but is _very_ unlikely
527
if (dumpLenLong >= (4L * 0x40000000)) {
528
throw new RuntimeException("Heap segment size overflow.");
529
}
530
531
// Save the current position
532
long currentPosition = fos.getChannel().position();
533
534
// seek the position to write length
535
fos.getChannel().position(currentSegmentStart);
536
537
// write length
538
int dumpLen = (int) dumpLenLong;
539
byte[] lenBytes = genByteArrayFromInt(dumpLen);
540
fos.write(lenBytes);
541
542
//Reset to previous current position
543
fos.getChannel().position(currentPosition);
544
}
545
546
// get the size in bytes for the requested type
547
private long getSizeForType(int type) throws IOException {
548
switch (type) {
549
case TypeArrayKlass.T_BOOLEAN:
550
return BOOLEAN_SIZE;
551
case TypeArrayKlass.T_INT:
552
return INT_SIZE;
553
case TypeArrayKlass.T_CHAR:
554
return CHAR_SIZE;
555
case TypeArrayKlass.T_SHORT:
556
return SHORT_SIZE;
557
case TypeArrayKlass.T_BYTE:
558
return BYTE_SIZE;
559
case TypeArrayKlass.T_LONG:
560
return LONG_SIZE;
561
case TypeArrayKlass.T_FLOAT:
562
return FLOAT_SIZE;
563
case TypeArrayKlass.T_DOUBLE:
564
return DOUBLE_SIZE;
565
default:
566
throw new RuntimeException(
567
"Should not reach here: Unknown type: " + type);
568
}
569
}
570
571
private int getArrayHeaderSize(boolean isObjectAarray) {
572
return isObjectAarray?
573
((int) BYTE_SIZE + 2 * (int) INT_SIZE + 2 * (int) OBJ_ID_SIZE):
574
(2 * (int) BYTE_SIZE + 2 * (int) INT_SIZE + (int) OBJ_ID_SIZE);
575
}
576
577
// Check if we need to truncate an array
578
private int calculateArrayMaxLength(long originalArrayLength,
579
int headerSize,
580
long typeSize,
581
String typeName) throws IOException {
582
583
long length = originalArrayLength;
584
585
// now get the current position to calculate length
586
long dumpEnd = fos.getChannel().position();
587
long originalLengthInBytes = originalArrayLength * typeSize;
588
589
// calculate the length of heap data
590
// only process when segmented heap dump is not used, since SegmentedOutputStream
591
// could create segment automatically.
592
long currentRecordLength = (dumpEnd - currentSegmentStart - 4L);
593
if ((!useSegmentedHeapDump) && currentRecordLength > 0 &&
594
(currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) {
595
fillInHeapRecordLength();
596
currentSegmentStart = 0;
597
writeHeapRecordPrologue();
598
currentRecordLength = 0;
599
}
600
601
// Calculate the max bytes we can use.
602
long maxBytes = (MAX_U4_VALUE - (headerSize + currentRecordLength));
603
604
if (originalLengthInBytes > maxBytes) {
605
length = maxBytes/typeSize;
606
System.err.println("WARNING: Cannot dump array of type " + typeName
607
+ " with length " + originalArrayLength
608
+ "; truncating to length " + length);
609
}
610
return (int) length;
611
}
612
613
private void writeClassDumpRecords() throws IOException {
614
ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
615
try {
616
cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
617
public void visit(Klass k) {
618
try {
619
writeHeapRecordPrologue();
620
writeClassDumpRecord(k);
621
writeHeapRecordEpilogue();
622
} catch (IOException e) {
623
throw new RuntimeException(e);
624
}
625
}
626
});
627
} catch (RuntimeException re) {
628
handleRuntimeException(re);
629
}
630
}
631
632
protected void writeClass(Instance instance) throws IOException {
633
Klass reflectedKlass = java_lang_Class.asKlass(instance);
634
// dump instance record only for primitive type Class objects.
635
// all other Class objects are covered by writeClassDumpRecords.
636
if (reflectedKlass == null) {
637
writeInstance(instance);
638
}
639
}
640
641
private void writeClassDumpRecord(Klass k) throws IOException {
642
out.writeByte((byte)HPROF_GC_CLASS_DUMP);
643
writeObjectID(k.getJavaMirror());
644
out.writeInt(DUMMY_STACK_TRACE_ID);
645
Klass superKlass = k.getJavaSuper();
646
if (superKlass != null) {
647
writeObjectID(superKlass.getJavaMirror());
648
} else {
649
writeObjectID(null);
650
}
651
652
if (k instanceof InstanceKlass) {
653
InstanceKlass ik = (InstanceKlass) k;
654
writeObjectID(ik.getClassLoader());
655
writeObjectID(null); // ik.getJavaMirror().getSigners());
656
writeObjectID(null); // ik.getJavaMirror().getProtectionDomain());
657
// two reserved id fields
658
writeObjectID(null);
659
writeObjectID(null);
660
List<Field> fields = getInstanceFields(ik);
661
int instSize = getSizeForFields(fields);
662
classDataCache.put(ik, new ClassData(instSize, fields));
663
out.writeInt(instSize);
664
665
// For now, ignore constant pool - HAT ignores too!
666
// output number of cp entries as zero.
667
out.writeShort((short) 0);
668
669
List<Field> declaredFields = ik.getImmediateFields();
670
List<Field> staticFields = new ArrayList<>();
671
List<Field> instanceFields = new ArrayList<>();
672
Iterator<Field> itr = null;
673
for (itr = declaredFields.iterator(); itr.hasNext();) {
674
Field field = itr.next();
675
if (field.isStatic()) {
676
staticFields.add(field);
677
} else {
678
instanceFields.add(field);
679
}
680
}
681
682
// dump static field descriptors
683
writeFieldDescriptors(staticFields, ik);
684
685
// dump instance field descriptors
686
writeFieldDescriptors(instanceFields, null);
687
} else {
688
if (k instanceof ObjArrayKlass) {
689
ObjArrayKlass oak = (ObjArrayKlass) k;
690
Klass bottomKlass = oak.getBottomKlass();
691
if (bottomKlass instanceof InstanceKlass) {
692
InstanceKlass ik = (InstanceKlass) bottomKlass;
693
writeObjectID(ik.getClassLoader());
694
writeObjectID(null); // ik.getJavaMirror().getSigners());
695
writeObjectID(null); // ik.getJavaMirror().getProtectionDomain());
696
} else {
697
writeObjectID(null);
698
writeObjectID(null);
699
writeObjectID(null);
700
}
701
} else {
702
writeObjectID(null);
703
writeObjectID(null);
704
writeObjectID(null);
705
}
706
// two reserved id fields
707
writeObjectID(null);
708
writeObjectID(null);
709
// write zero instance size -- as instance size
710
// is variable for arrays.
711
out.writeInt(0);
712
// no constant pool for array klasses
713
out.writeShort((short) 0);
714
// no static fields for array klasses
715
out.writeShort((short) 0);
716
// no instance fields for array klasses
717
out.writeShort((short) 0);
718
}
719
}
720
721
private void dumpStackTraces() throws IOException {
722
// write a HPROF_TRACE record without any frames to be referenced as object alloc sites
723
writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE );
724
out.writeInt(DUMMY_STACK_TRACE_ID);
725
out.writeInt(0); // thread number
726
out.writeInt(0); // frame count
727
728
int frameSerialNum = 0;
729
int numThreads = 0;
730
Threads threads = VM.getVM().getThreads();
731
for (int i = 0; i < threads.getNumberOfThreads(); i++) {
732
JavaThread thread = threads.getJavaThreadAt(i);
733
Oop threadObj = thread.getThreadObj();
734
if (threadObj != null && !thread.isExiting() && !thread.isHiddenFromExternalView()) {
735
736
// dump thread stack trace
737
ThreadStackTrace st = new ThreadStackTrace(thread);
738
st.dumpStack(-1);
739
numThreads++;
740
741
// write HPROF_FRAME records for this thread's stack trace
742
int depth = st.getStackDepth();
743
int threadFrameStart = frameSerialNum;
744
for (int j=0; j < depth; j++) {
745
StackFrameInfo frame = st.stackFrameAt(j);
746
Method m = frame.getMethod();
747
int classSerialNum = KlassMap.indexOf(m.getMethodHolder()) + 1;
748
// the class serial number starts from 1
749
assert classSerialNum > 0:"class not found";
750
dumpStackFrame(++frameSerialNum, classSerialNum, m, frame.getBCI());
751
}
752
753
// write HPROF_TRACE record for one thread
754
writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE + depth * (int)VM.getVM().getOopSize());
755
int stackSerialNum = numThreads + DUMMY_STACK_TRACE_ID;
756
out.writeInt(stackSerialNum); // stack trace serial number
757
out.writeInt(numThreads); // thread serial number
758
out.writeInt(depth); // frame count
759
for (int j=1; j <= depth; j++) {
760
writeObjectID(threadFrameStart + j);
761
}
762
}
763
}
764
}
765
766
private void dumpStackFrame(int frameSN, int classSN, Method m, int bci) throws IOException {
767
int lineNumber;
768
if (m.isNative()) {
769
lineNumber = -3; // native frame
770
} else {
771
lineNumber = m.getLineNumberFromBCI(bci);
772
}
773
// First dump UTF8 if needed
774
writeSymbol(m.getName()); // method's name
775
writeSymbol(m.getSignature()); // method's signature
776
writeSymbol(m.getMethodHolder().getSourceFileName()); // source file name
777
// Then write FRAME descriptor
778
writeHeader(HPROF_FRAME, 4 * (int)VM.getVM().getOopSize() + 2 * (int)INT_SIZE);
779
writeObjectID(frameSN); // frame serial number
780
writeSymbolID(m.getName()); // method's name
781
writeSymbolID(m.getSignature()); // method's signature
782
writeSymbolID(m.getMethodHolder().getSourceFileName()); // source file name
783
out.writeInt(classSN); // class serial number
784
out.writeInt(lineNumber); // line number
785
}
786
787
protected void writeJavaThread(JavaThread jt, int index) throws IOException {
788
out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ);
789
writeObjectID(jt.getThreadObj());
790
out.writeInt(index);
791
out.writeInt(DUMMY_STACK_TRACE_ID);
792
writeLocalJNIHandles(jt, index);
793
}
794
795
protected void writeLocalJNIHandles(JavaThread jt, int index) throws IOException {
796
final int threadIndex = index;
797
JNIHandleBlock blk = jt.activeHandles();
798
if (blk != null) {
799
try {
800
blk.oopsDo(new AddressVisitor() {
801
public void visitAddress(Address handleAddr) {
802
try {
803
if (handleAddr != null) {
804
OopHandle oopHandle = handleAddr.getOopHandleAt(0);
805
Oop oop = objectHeap.newOop(oopHandle);
806
// exclude JNI handles hotspot internal objects
807
if (oop != null && isJavaVisible(oop)) {
808
out.writeByte((byte) HPROF_GC_ROOT_JNI_LOCAL);
809
writeObjectID(oop);
810
out.writeInt(threadIndex);
811
out.writeInt(EMPTY_FRAME_DEPTH);
812
}
813
}
814
} catch (IOException exp) {
815
throw new RuntimeException(exp);
816
}
817
}
818
public void visitCompOopAddress(Address handleAddr) {
819
throw new RuntimeException(
820
" Should not reach here. JNIHandles are not compressed \n");
821
}
822
});
823
} catch (RuntimeException re) {
824
handleRuntimeException(re);
825
}
826
}
827
}
828
829
protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
830
OopHandle oopHandle = handleAddr.getOopHandleAt(0);
831
Oop oop = objectHeap.newOop(oopHandle);
832
// exclude JNI handles of hotspot internal objects
833
if (oop != null && isJavaVisible(oop)) {
834
out.writeByte((byte) HPROF_GC_ROOT_JNI_GLOBAL);
835
writeObjectID(oop);
836
// use JNIHandle address as ID
837
writeObjectID(getAddressValue(handleAddr));
838
}
839
}
840
841
protected void writeObjectArray(ObjArray array) throws IOException {
842
int headerSize = getArrayHeaderSize(true);
843
final int length = calculateArrayMaxLength(array.getLength(),
844
headerSize,
845
OBJ_ID_SIZE,
846
"Object");
847
out.writeByte((byte) HPROF_GC_OBJ_ARRAY_DUMP);
848
writeObjectID(array);
849
out.writeInt(DUMMY_STACK_TRACE_ID);
850
out.writeInt(length);
851
writeObjectID(array.getKlass().getJavaMirror());
852
for (int index = 0; index < length; index++) {
853
OopHandle handle = array.getOopHandleAt(index);
854
writeObjectID(getAddressValue(handle));
855
}
856
}
857
858
protected void writePrimitiveArray(TypeArray array) throws IOException {
859
int headerSize = getArrayHeaderSize(false);
860
TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
861
final int type = (int) tak.getElementType();
862
final String typeName = tak.getElementTypeName();
863
final long typeSize = getSizeForType(type);
864
final int length = calculateArrayMaxLength(array.getLength(),
865
headerSize,
866
typeSize,
867
typeName);
868
out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP);
869
writeObjectID(array);
870
out.writeInt(DUMMY_STACK_TRACE_ID);
871
out.writeInt(length);
872
out.writeByte((byte) type);
873
switch (type) {
874
case TypeArrayKlass.T_BOOLEAN:
875
writeBooleanArray(array, length);
876
break;
877
case TypeArrayKlass.T_CHAR:
878
writeCharArray(array, length);
879
break;
880
case TypeArrayKlass.T_FLOAT:
881
writeFloatArray(array, length);
882
break;
883
case TypeArrayKlass.T_DOUBLE:
884
writeDoubleArray(array, length);
885
break;
886
case TypeArrayKlass.T_BYTE:
887
writeByteArray(array, length);
888
break;
889
case TypeArrayKlass.T_SHORT:
890
writeShortArray(array, length);
891
break;
892
case TypeArrayKlass.T_INT:
893
writeIntArray(array, length);
894
break;
895
case TypeArrayKlass.T_LONG:
896
writeLongArray(array, length);
897
break;
898
default:
899
throw new RuntimeException(
900
"Should not reach here: Unknown type: " + type);
901
}
902
}
903
904
private void writeBooleanArray(TypeArray array, int length) throws IOException {
905
for (int index = 0; index < length; index++) {
906
long offset = BOOLEAN_BASE_OFFSET + index * BOOLEAN_SIZE;
907
out.writeBoolean(array.getHandle().getJBooleanAt(offset));
908
}
909
}
910
911
private void writeByteArray(TypeArray array, int length) throws IOException {
912
for (int index = 0; index < length; index++) {
913
long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
914
out.writeByte(array.getHandle().getJByteAt(offset));
915
}
916
}
917
918
private void writeShortArray(TypeArray array, int length) throws IOException {
919
for (int index = 0; index < length; index++) {
920
long offset = SHORT_BASE_OFFSET + index * SHORT_SIZE;
921
out.writeShort(array.getHandle().getJShortAt(offset));
922
}
923
}
924
925
private void writeIntArray(TypeArray array, int length) throws IOException {
926
for (int index = 0; index < length; index++) {
927
long offset = INT_BASE_OFFSET + index * INT_SIZE;
928
out.writeInt(array.getHandle().getJIntAt(offset));
929
}
930
}
931
932
private void writeLongArray(TypeArray array, int length) throws IOException {
933
for (int index = 0; index < length; index++) {
934
long offset = LONG_BASE_OFFSET + index * LONG_SIZE;
935
out.writeLong(array.getHandle().getJLongAt(offset));
936
}
937
}
938
939
private void writeCharArray(TypeArray array, int length) throws IOException {
940
for (int index = 0; index < length; index++) {
941
long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;
942
out.writeChar(array.getHandle().getJCharAt(offset));
943
}
944
}
945
946
private void writeFloatArray(TypeArray array, int length) throws IOException {
947
for (int index = 0; index < length; index++) {
948
long offset = FLOAT_BASE_OFFSET + index * FLOAT_SIZE;
949
out.writeFloat(array.getHandle().getJFloatAt(offset));
950
}
951
}
952
953
private void writeDoubleArray(TypeArray array, int length) throws IOException {
954
for (int index = 0; index < length; index++) {
955
long offset = DOUBLE_BASE_OFFSET + index * DOUBLE_SIZE;
956
out.writeDouble(array.getHandle().getJDoubleAt(offset));
957
}
958
}
959
960
protected void writeInstance(Instance instance) throws IOException {
961
Klass klass = instance.getKlass();
962
if (klass.getClassLoaderData() == null) {
963
// Ignoring this object since the corresponding Klass is not loaded.
964
// Might be a dormant archive object.
965
return;
966
}
967
968
out.writeByte((byte) HPROF_GC_INSTANCE_DUMP);
969
writeObjectID(instance);
970
out.writeInt(DUMMY_STACK_TRACE_ID);
971
writeObjectID(klass.getJavaMirror());
972
973
ClassData cd = (ClassData) classDataCache.get(klass);
974
975
if (Assert.ASSERTS_ENABLED) {
976
Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getAddress());
977
}
978
List<Field> fields = cd.fields;
979
int size = cd.instSize;
980
out.writeInt(size);
981
for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {
982
writeField(itr.next(), instance);
983
}
984
}
985
986
//-- Internals only below this point
987
988
private void writeFieldDescriptors(List<Field> fields, InstanceKlass ik)
989
throws IOException {
990
// ik == null for instance fields.
991
out.writeShort((short) fields.size());
992
for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {
993
Field field = itr.next();
994
Symbol name = field.getName();
995
writeSymbolID(name);
996
char typeCode = (char) field.getSignature().getByteAt(0);
997
int kind = signatureToHprofKind(typeCode);
998
out.writeByte((byte)kind);
999
if (ik != null) {
1000
// static field
1001
writeField(field, ik.getJavaMirror());
1002
}
1003
}
1004
}
1005
1006
public static int signatureToHprofKind(char ch) {
1007
switch (ch) {
1008
case JVM_SIGNATURE_CLASS:
1009
case JVM_SIGNATURE_ARRAY:
1010
return HPROF_NORMAL_OBJECT;
1011
case JVM_SIGNATURE_BOOLEAN:
1012
return HPROF_BOOLEAN;
1013
case JVM_SIGNATURE_CHAR:
1014
return HPROF_CHAR;
1015
case JVM_SIGNATURE_FLOAT:
1016
return HPROF_FLOAT;
1017
case JVM_SIGNATURE_DOUBLE:
1018
return HPROF_DOUBLE;
1019
case JVM_SIGNATURE_BYTE:
1020
return HPROF_BYTE;
1021
case JVM_SIGNATURE_SHORT:
1022
return HPROF_SHORT;
1023
case JVM_SIGNATURE_INT:
1024
return HPROF_INT;
1025
case JVM_SIGNATURE_LONG:
1026
return HPROF_LONG;
1027
default:
1028
throw new RuntimeException("should not reach here");
1029
}
1030
}
1031
1032
private void writeField(Field field, Oop oop) throws IOException {
1033
char typeCode = (char) field.getSignature().getByteAt(0);
1034
switch (typeCode) {
1035
case JVM_SIGNATURE_BOOLEAN:
1036
out.writeBoolean(((BooleanField)field).getValue(oop));
1037
break;
1038
case JVM_SIGNATURE_CHAR:
1039
out.writeChar(((CharField)field).getValue(oop));
1040
break;
1041
case JVM_SIGNATURE_BYTE:
1042
out.writeByte(((ByteField)field).getValue(oop));
1043
break;
1044
case JVM_SIGNATURE_SHORT:
1045
out.writeShort(((ShortField)field).getValue(oop));
1046
break;
1047
case JVM_SIGNATURE_INT:
1048
out.writeInt(((IntField)field).getValue(oop));
1049
break;
1050
case JVM_SIGNATURE_LONG:
1051
out.writeLong(((LongField)field).getValue(oop));
1052
break;
1053
case JVM_SIGNATURE_FLOAT:
1054
out.writeFloat(((FloatField)field).getValue(oop));
1055
break;
1056
case JVM_SIGNATURE_DOUBLE:
1057
out.writeDouble(((DoubleField)field).getValue(oop));
1058
break;
1059
case JVM_SIGNATURE_CLASS:
1060
case JVM_SIGNATURE_ARRAY: {
1061
if (VM.getVM().isCompressedOopsEnabled()) {
1062
OopHandle handle = ((NarrowOopField)field).getValueAsOopHandle(oop);
1063
writeObjectID(getAddressValue(handle));
1064
} else {
1065
OopHandle handle = ((OopField)field).getValueAsOopHandle(oop);
1066
writeObjectID(getAddressValue(handle));
1067
}
1068
break;
1069
}
1070
default:
1071
throw new RuntimeException("should not reach here");
1072
}
1073
}
1074
1075
private void writeHeader(int tag, int len) throws IOException {
1076
out.writeByte((byte)tag);
1077
out.writeInt(0); // current ticks
1078
out.writeInt(len);
1079
}
1080
1081
private void writeDummyTrace() throws IOException {
1082
writeHeader(HPROF_TRACE, 3 * 4);
1083
out.writeInt(DUMMY_STACK_TRACE_ID);
1084
out.writeInt(0);
1085
out.writeInt(0);
1086
}
1087
1088
private void writeClassSymbols(Klass k) throws IOException {
1089
writeSymbol(k.getName());
1090
if (k instanceof InstanceKlass) {
1091
InstanceKlass ik = (InstanceKlass) k;
1092
List<Field> declaredFields = ik.getImmediateFields();
1093
for (Iterator<Field> itr = declaredFields.iterator(); itr.hasNext();) {
1094
Field field = itr.next();
1095
writeSymbol(field.getName());
1096
}
1097
}
1098
}
1099
1100
private void writeSymbols() throws IOException {
1101
// Write all the symbols that are used by the classes
1102
ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
1103
try {
1104
cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
1105
public void visit(Klass k) {
1106
try {
1107
writeClassSymbols(k);
1108
} catch (IOException e) {
1109
throw new RuntimeException(e);
1110
}
1111
}
1112
});
1113
} catch (RuntimeException re) {
1114
handleRuntimeException(re);
1115
}
1116
}
1117
1118
private void writeSymbol(Symbol sym) throws IOException {
1119
// If name is already written don't write it again.
1120
if (names.add(sym)) {
1121
if(sym != null) {
1122
byte[] buf = sym.asString().getBytes("UTF-8");
1123
writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE);
1124
writeSymbolID(sym);
1125
out.write(buf);
1126
} else {
1127
writeHeader(HPROF_UTF8, 0 + OBJ_ID_SIZE);
1128
writeSymbolID(null);
1129
}
1130
}
1131
}
1132
1133
private void writeClasses() throws IOException {
1134
// write class list (id, name) association
1135
ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
1136
try {
1137
cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
1138
public void visit(Klass k) {
1139
try {
1140
Instance clazz = k.getJavaMirror();
1141
writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
1142
out.writeInt(serialNum);
1143
writeObjectID(clazz);
1144
KlassMap.add(serialNum - 1, k);
1145
out.writeInt(DUMMY_STACK_TRACE_ID);
1146
writeSymbolID(k.getName());
1147
serialNum++;
1148
} catch (IOException exp) {
1149
throw new RuntimeException(exp);
1150
}
1151
}
1152
});
1153
} catch (RuntimeException re) {
1154
handleRuntimeException(re);
1155
}
1156
}
1157
1158
// writes hprof binary file header
1159
private void writeFileHeader() throws IOException {
1160
// version string
1161
out.writeBytes(HPROF_HEADER_1_0_2);
1162
out.writeByte((byte)'\0');
1163
1164
// write identifier size. we use pointers as identifiers.
1165
out.writeInt(OBJ_ID_SIZE);
1166
1167
// timestamp -- file creation time.
1168
out.writeLong(System.currentTimeMillis());
1169
}
1170
1171
// writes unique ID for an object
1172
private void writeObjectID(Oop oop) throws IOException {
1173
OopHandle handle = (oop != null)? oop.getHandle() : null;
1174
long address = getAddressValue(handle);
1175
writeObjectID(address);
1176
}
1177
1178
private void writeSymbolID(Symbol sym) throws IOException {
1179
assert names.contains(sym);
1180
long address = (sym != null) ? getAddressValue(sym.getAddress()) : getAddressValue(null);
1181
writeObjectID(address);
1182
}
1183
1184
private void writeObjectID(long address) throws IOException {
1185
if (OBJ_ID_SIZE == 4) {
1186
out.writeInt((int) address);
1187
} else {
1188
out.writeLong(address);
1189
}
1190
}
1191
1192
private long getAddressValue(Address addr) {
1193
return (addr == null)? 0L : dbg.getAddressValue(addr);
1194
}
1195
1196
// get all declared as well as inherited (directly/indirectly) fields
1197
private static List<Field> getInstanceFields(InstanceKlass ik) {
1198
InstanceKlass klass = ik;
1199
List<Field> res = new ArrayList<>();
1200
while (klass != null) {
1201
List<Field> curFields = klass.getImmediateFields();
1202
for (Iterator<Field> itr = curFields.iterator(); itr.hasNext();) {
1203
Field f = itr.next();
1204
if (! f.isStatic()) {
1205
res.add(f);
1206
}
1207
}
1208
klass = (InstanceKlass) klass.getSuper();
1209
}
1210
return res;
1211
}
1212
1213
// get size in bytes (in stream) required for given fields. Note
1214
// that this is not the same as object size in heap. The size in
1215
// heap will include size of padding/alignment bytes as well.
1216
private int getSizeForFields(List<Field> fields) {
1217
int size = 0;
1218
for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {
1219
Field field = itr.next();
1220
char typeCode = (char) field.getSignature().getByteAt(0);
1221
switch (typeCode) {
1222
case JVM_SIGNATURE_BOOLEAN:
1223
case JVM_SIGNATURE_BYTE:
1224
size++;
1225
break;
1226
case JVM_SIGNATURE_CHAR:
1227
case JVM_SIGNATURE_SHORT:
1228
size += 2;
1229
break;
1230
case JVM_SIGNATURE_INT:
1231
case JVM_SIGNATURE_FLOAT:
1232
size += 4;
1233
break;
1234
case JVM_SIGNATURE_CLASS:
1235
case JVM_SIGNATURE_ARRAY:
1236
size += OBJ_ID_SIZE;
1237
break;
1238
case JVM_SIGNATURE_LONG:
1239
case JVM_SIGNATURE_DOUBLE:
1240
size += 8;
1241
break;
1242
default:
1243
throw new RuntimeException("should not reach here");
1244
}
1245
}
1246
return size;
1247
}
1248
1249
private boolean isCompression() {
1250
return (gzLevel >= 1 && gzLevel <= 9);
1251
}
1252
1253
// Convert integer to byte array with BIG_ENDIAN byte order.
1254
private static byte[] genByteArrayFromInt(int value) {
1255
ByteBuffer intBuffer = ByteBuffer.allocate(4);
1256
intBuffer.order(ByteOrder.BIG_ENDIAN);
1257
intBuffer.putInt(value);
1258
return intBuffer.array();
1259
}
1260
1261
// We don't have allocation site info. We write a dummy
1262
// stack trace with this id.
1263
private static final int DUMMY_STACK_TRACE_ID = 1;
1264
private static final int EMPTY_FRAME_DEPTH = -1;
1265
1266
private DataOutputStream out;
1267
private FileOutputStream fos;
1268
private SegmentedOutputStream hprofBufferedOut;
1269
private Debugger dbg;
1270
private ObjectHeap objectHeap;
1271
private ArrayList<Klass> KlassMap;
1272
private int gzLevel;
1273
1274
// oopSize of the debuggee
1275
private int OBJ_ID_SIZE;
1276
1277
// Added for hprof file format 1.0.2 support
1278
private boolean useSegmentedHeapDump;
1279
private long currentSegmentStart;
1280
1281
private long BOOLEAN_BASE_OFFSET;
1282
private long BYTE_BASE_OFFSET;
1283
private long CHAR_BASE_OFFSET;
1284
private long SHORT_BASE_OFFSET;
1285
private long INT_BASE_OFFSET;
1286
private long LONG_BASE_OFFSET;
1287
private long FLOAT_BASE_OFFSET;
1288
private long DOUBLE_BASE_OFFSET;
1289
private long OBJECT_BASE_OFFSET;
1290
1291
private long BOOLEAN_SIZE;
1292
private long BYTE_SIZE;
1293
private long CHAR_SIZE;
1294
private long SHORT_SIZE;
1295
private long INT_SIZE;
1296
private long LONG_SIZE;
1297
private long FLOAT_SIZE;
1298
private long DOUBLE_SIZE;
1299
1300
private static class ClassData {
1301
int instSize;
1302
List<Field> fields;
1303
1304
ClassData(int instSize, List<Field> fields) {
1305
this.instSize = instSize;
1306
this.fields = fields;
1307
}
1308
}
1309
1310
private Map<InstanceKlass, ClassData> classDataCache = new HashMap<>();
1311
1312
/**
1313
* The class implements a buffered output stream for segmented data dump.
1314
* It is used inside HeapHprofBinWritter only for heap dump.
1315
* Because the current implementation of segmented heap dump needs to update
1316
* the segment size at segment header, and because it is hard to modify the
1317
* compressed data after they are written to file, this class first saves the
1318
* uncompressed data into an internal buffer, and then writes through to the
1319
* GZIPOutputStream when the whole segmented data are ready and the size is updated.
1320
* If the data to be written are larger than internal buffer, or the internal buffer
1321
* is full, the internal buffer will be extend to a larger one.
1322
* This class defines a switch to turn on/off the segmented mode. If turned off,
1323
* it behaves the same as BufferedOutputStream.
1324
* */
1325
private class SegmentedOutputStream extends BufferedOutputStream {
1326
/**
1327
* Creates a new buffered output stream to support segmented heap dump data.
1328
*
1329
* @param out the underlying output stream.
1330
* @param allowSegmented whether allow segmental dump.
1331
*/
1332
public SegmentedOutputStream(OutputStream out, boolean allowSegmented) {
1333
super(out, 8192);
1334
segmentMode = false;
1335
this.allowSegmented = allowSegmented;
1336
segmentBuffer = new byte[SEGMENT_BUFFER_SIZE];
1337
segmentWritten = 0;
1338
}
1339
1340
/**
1341
* Creates a new buffered output stream to support segmented heap dump data.
1342
*
1343
* @param out the underlying output stream.
1344
*/
1345
public SegmentedOutputStream(OutputStream out) {
1346
this(out, true);
1347
}
1348
1349
/**
1350
* Writes the specified byte to this buffered output stream.
1351
*
1352
* @param b the byte to be written.
1353
* @throws IOException if an I/O error occurs.
1354
*/
1355
@Override
1356
public synchronized void write(int b) throws IOException {
1357
if (segmentMode) {
1358
if (segmentWritten == 0) {
1359
// At the begining of the segment.
1360
writeSegmentHeader();
1361
} else if (segmentWritten == segmentBuffer.length) {
1362
// Internal buffer is full, extend a larger one.
1363
int newSize = segmentBuffer.length + SEGMENT_BUFFER_INC_SIZE;
1364
byte newBuf[] = new byte[newSize];
1365
System.arraycopy(segmentBuffer, 0, newBuf, 0, segmentWritten);
1366
segmentBuffer = newBuf;
1367
}
1368
segmentBuffer[segmentWritten++] = (byte)b;
1369
return;
1370
}
1371
super.write(b);
1372
}
1373
1374
/**
1375
* Writes {@code len} bytes from the specified byte array
1376
* starting at offset {@code off} to this output stream.
1377
*
1378
* @param b the data.
1379
* @param off the start offset in the data.
1380
* @param len the number of bytes to write.
1381
* @throws IOException if an I/O error occurs.
1382
*/
1383
@Override
1384
public synchronized void write(byte b[], int off, int len) throws IOException {
1385
if (segmentMode) {
1386
if (segmentWritten == 0) {
1387
writeSegmentHeader();
1388
}
1389
// Data size is larger than segment buffer length, extend segment buffer.
1390
if (segmentWritten + len > segmentBuffer.length) {
1391
int newSize = segmentBuffer.length + Math.max(SEGMENT_BUFFER_INC_SIZE, len);
1392
byte newBuf[] = new byte[newSize];
1393
System.arraycopy(segmentBuffer, 0, newBuf, 0, segmentWritten);
1394
segmentBuffer = newBuf;
1395
}
1396
System.arraycopy(b, off, segmentBuffer, segmentWritten, len);
1397
segmentWritten += len;
1398
return;
1399
}
1400
super.write(b, off, len);
1401
}
1402
1403
/**
1404
* Flushes this buffered output stream. This forces any buffered
1405
* output bytes to be written out to the underlying output stream.
1406
*
1407
* @throws IOException if an I/O error occurs.
1408
* @see java.io.FilterOutputStream#out
1409
*/
1410
@Override
1411
public synchronized void flush() throws IOException {
1412
if (segmentMode) {
1413
// The case that nothing has been written in segment.
1414
if (segmentWritten == 0) return;
1415
// There must be more data than just header size written for non-empty segment.
1416
assert segmentWritten > SEGMENT_HEADER_SIZE
1417
: "invalid header in segmented mode";
1418
1419
if (segmentWritten > (segmentBuffer.length)) {
1420
throw new RuntimeException("Heap segment size overflow.");
1421
}
1422
1423
if (segmentWritten > SEGMENT_HEADER_SIZE) {
1424
fillSegmentSize(segmentWritten - SEGMENT_HEADER_SIZE);
1425
super.write(segmentBuffer, 0, segmentWritten);
1426
super.flush();
1427
segmentWritten = 0;
1428
}
1429
return;
1430
}
1431
super.flush();
1432
}
1433
1434
/**
1435
* Enters segmented mode, flush buffered data and set flag.
1436
*/
1437
public void enterSegmentMode() throws IOException {
1438
if (allowSegmented && !segmentMode && segmentWritten == 0) {
1439
super.flush();
1440
segmentMode = true;
1441
segmentWritten = 0;
1442
}
1443
}
1444
1445
/**
1446
* Before finish, flush all data in buffer.
1447
*/
1448
public void finish() throws IOException {
1449
if (allowSegmented && segmentMode) {
1450
flush();
1451
assert segmentWritten == 0;
1452
segmentMode = false;
1453
}
1454
}
1455
1456
/**
1457
* Exits segmented mode, flush segmented data.
1458
* @param force flush data regardless whether the buffer is full
1459
*/
1460
public void exitSegmentMode() throws IOException {
1461
if (allowSegmented && segmentMode && shouldFlush()) {
1462
flush();
1463
assert segmentWritten == 0;
1464
segmentMode = false;
1465
}
1466
}
1467
1468
1469
/**
1470
* Check whether the data should be flush based on data saved in
1471
* segmentBuffer.
1472
* This method is used to control the segments number and the memory usage.
1473
* If segment is too small, there will be lots segments in final dump file.
1474
* If it is too large, lots of memory is used in RAM.
1475
*/
1476
private boolean shouldFlush() {
1477
// return true if data in segmentBuffer has been extended.
1478
return segmentWritten > SEGMENT_BUFFER_SIZE;
1479
}
1480
1481
/**
1482
* Writes the write segment header into internal buffer.
1483
*/
1484
private void writeSegmentHeader() {
1485
assert segmentWritten == 0;
1486
segmentBuffer[segmentWritten++] = (byte)HPROF_HEAP_DUMP_SEGMENT;
1487
writeInteger(0);
1488
// segment size, write dummy length of 0 and we'll fix it later.
1489
writeInteger(0);
1490
}
1491
1492
/**
1493
* Fills the segmented data size into the header.
1494
*/
1495
private void fillSegmentSize(int size) {
1496
byte[] lenBytes = genByteArrayFromInt(size);
1497
System.arraycopy(lenBytes, 0, segmentBuffer, 5, 4);
1498
}
1499
1500
/**
1501
* Writes an {@code int} to the internal segment buffer
1502
* {@code written} is incremented by {@code 4}.
1503
*/
1504
private final void writeInteger(int value) {
1505
byte[] intBytes = genByteArrayFromInt(value);
1506
System.arraycopy(intBytes, 0, segmentBuffer, segmentWritten, 4);
1507
segmentWritten += 4;
1508
}
1509
1510
// The buffer size for segmentBuffer.
1511
// Since it is hard to calculate and fill the data size of an segment in compressed
1512
// data, making the segmented data stored in this buffer could help rewrite the data
1513
// size before the segmented data are written to underlying GZIPOutputStream.
1514
private static final int SEGMENT_BUFFER_SIZE = 1 << 20;
1515
// Buffer size used to extend the segment buffer.
1516
private static final int SEGMENT_BUFFER_INC_SIZE = 1 << 10;
1517
// Headers:
1518
// 1 byte for HPROF_HEAP_DUMP_SEGMENT
1519
// 4 bytes for timestamp
1520
// 4 bytes for size
1521
private static final int SEGMENT_HEADER_SIZE = 9;
1522
// Segment support.
1523
private boolean segmentMode;
1524
private boolean allowSegmented;
1525
private byte segmentBuffer[];
1526
private int segmentWritten;
1527
}
1528
}
1529
1530