Skip to content

Commit b0a5476

Browse files
committed
GH-409 - improve the accuracy of the instance size
1 parent 03b25dd commit b0a5476

File tree

9 files changed

+1362
-1195
lines changed

9 files changed

+1362
-1195
lines changed

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/ArrayDump.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@
3434
* @author Tomas Hurka
3535
*/
3636
abstract class ArrayDump extends InstanceDump {
37-
//~ Static fields/initializers -----------------------------------------------------------------------------------------------
38-
39-
static int HPROF_ARRAY_OVERHEAD = 8; // difference between size of java.lang.Object and java.lang.Object[0]
4037

4138
//~ Constructors -------------------------------------------------------------------------------------------------------------
4239

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/ClassDump.java

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.Map;
4040
import java.util.NoSuchElementException;
4141
import java.util.Set;
42+
import static org.graalvm.visualvm.lib.jfluid.heap.ObjectSizeSettings.OBJECT_ALIGNMENT;
4243

4344

4445
/**
@@ -60,6 +61,7 @@ class ClassDump extends HprofObject implements JavaClass {
6061

6162
final ClassDumpSegment classDumpSegment;
6263
private int instances;
64+
private int instanceSize;
6365
private long firstInstanceOffset;
6466
private long loadClassOffset;
6567
private long retainedSizeByClass;
@@ -75,10 +77,17 @@ class ClassDump extends HprofObject implements JavaClass {
7577
//~ Methods ------------------------------------------------------------------------------------------------------------------
7678

7779
public long getAllInstancesSize() {
78-
Long allInstancesSizeArr = classDumpSegment.arrayMap.get(this);
79-
80-
if (allInstancesSizeArr != null) {
81-
return allInstancesSizeArr.longValue();
80+
long[] totalElements = classDumpSegment.arrayMap.get(this);
81+
82+
if (totalElements != null) {
83+
int elSize = classDumpSegment.getArrayElSize(this);
84+
int minArrayInstanceSize = classDumpSegment.sizeSettings.getMinimumInstanceSize() + ObjectSizeSettings.ARRAY_OVERHEAD;
85+
long size = totalElements[OBJECT_ALIGNMENT]*OBJECT_ALIGNMENT*elSize;
86+
for (int i=0; i<OBJECT_ALIGNMENT; i++) {
87+
long psize = classDumpSegment.alignObjectSize(minArrayInstanceSize+elSize*i);
88+
size += psize*totalElements[i];
89+
}
90+
return size;
8291
}
8392

8493
return ((long)getInstancesCount()) * getInstanceSize();
@@ -123,12 +132,11 @@ public int getInstanceSize() {
123132
if (isArray()) {
124133
return -1;
125134
}
126-
127-
int size = getRawInstanceSize();
128-
if (!classDumpSegment.newSize) {
129-
size += classDumpSegment.getMinimumInstanceSize();
135+
int size = getUnalignedSize();
136+
if (classDumpSegment.newSize) {
137+
return size;
130138
}
131-
return size;
139+
return (int)classDumpSegment.alignObjectSize(size);
132140
}
133141

134142
public long getRetainedSizeByClass() {
@@ -271,6 +279,29 @@ public Heap getHeap() {
271279
return getHprof();
272280
}
273281

282+
private int getUnalignedSize() {
283+
if (instanceSize == 0) {
284+
int size;
285+
if (classDumpSegment.newSize) {
286+
size = getRawInstanceSize();
287+
} else {
288+
ClassDump jcls = (ClassDump) getSuperClass();
289+
if (jcls == null) {
290+
size = classDumpSegment.sizeSettings.getMinimumInstanceSize();
291+
} else {
292+
size = jcls.getUnalignedSize();
293+
}
294+
HprofHeap heap = getHprof();
295+
for (Field f : getFields()) {
296+
HprofField hf = (HprofField)f;
297+
size+=classDumpSegment.sizeSettings.getElementSize(hf.getValueType());
298+
}
299+
}
300+
instanceSize = size;
301+
}
302+
return instanceSize;
303+
}
304+
274305
private List<Field> computeFields() {
275306
HprofByteBuffer buffer = getHprofBuffer();
276307
long offset = fileOffset + getInstanceFieldOffset();

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/ClassDumpSegment.java

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import java.util.List;
3838
import java.util.Map;
3939
import java.util.regex.Pattern;
40-
40+
import static org.graalvm.visualvm.lib.jfluid.heap.ObjectSizeSettings.*;
4141

4242
/**
4343
*
@@ -47,8 +47,9 @@ class ClassDumpSegment extends TagBounds {
4747
//~ Instance fields ----------------------------------------------------------------------------------------------------------
4848

4949
HprofHeap hprofHeap;
50+
final ObjectSizeSettings sizeSettings;
5051
// Map <JavaClass represeting array,Long - allInstanceSize>
51-
Map<JavaClass,Long> arrayMap;
52+
Map<JavaClass,long[]> arrayMap;
5253
final int classIDOffset;
5354
final int classLoaderIDOffset;
5455
final int constantPoolSizeOffset;
@@ -57,7 +58,6 @@ class ClassDumpSegment extends TagBounds {
5758
final int fieldTypeOffset;
5859
final int fieldValueOffset;
5960
final int instanceSizeOffset;
60-
final int minimumInstanceSize;
6161
final int protectionDomainIDOffset;
6262
final int reserved1;
6363
final int reserver2;
@@ -69,6 +69,7 @@ class ClassDumpSegment extends TagBounds {
6969
Map<JavaClass,List<Field>> fieldsCache;
7070
private List<JavaClass> classes;
7171
private Map<Integer,JavaClass> primitiveArrayMap;
72+
private Map<JavaClass,Integer> primitiveTypeMap;
7273

7374
//~ Constructors -------------------------------------------------------------------------------------------------------------
7475

@@ -77,6 +78,7 @@ class ClassDumpSegment extends TagBounds {
7778

7879
int idSize = heap.dumpBuffer.getIDSize();
7980
hprofHeap = heap;
81+
sizeSettings = new ObjectSizeSettings(hprofHeap);
8082
// initialize offsets
8183
classIDOffset = 1;
8284
stackTraceSerialNumberOffset = classIDOffset + idSize;
@@ -94,8 +96,6 @@ class ClassDumpSegment extends TagBounds {
9496
fieldValueOffset = fieldTypeOffset + 1;
9597

9698
fieldSize = fieldTypeOffset + 1;
97-
98-
minimumInstanceSize = 2 * idSize;
9999

100100
fieldsCache = Collections.synchronizedMap(new FieldsCache());
101101
}
@@ -149,8 +149,11 @@ Collection<JavaClass> getJavaClassesByRegExp(String regexp) {
149149
return result;
150150
}
151151

152-
int getMinimumInstanceSize() {
153-
return minimumInstanceSize;
152+
long getArraySize(byte type, int elements) {
153+
long size;
154+
long elementSize = sizeSettings.getElementSize(type);
155+
size = sizeSettings.getMinimumInstanceSize() + ARRAY_OVERHEAD + (elementSize * elements);
156+
return alignObjectSize(size);
154157
}
155158

156159
ClassDump getPrimitiveArrayClass(byte type) {
@@ -175,30 +178,27 @@ Map getClassIdToClassMap() {
175178

176179
void addInstanceSize(ClassDump cls, int tag, long instanceOffset) {
177180
if ((tag == HprofHeap.OBJECT_ARRAY_DUMP) || (tag == HprofHeap.PRIMITIVE_ARRAY_DUMP)) {
178-
Long sizeLong = arrayMap.get(cls);
181+
long sizeLong[] = arrayMap.get(cls);
179182
long size = 0;
180183
HprofByteBuffer dumpBuffer = hprofHeap.dumpBuffer;
181184
int idSize = dumpBuffer.getIDSize();
182185
long elementsOffset = instanceOffset + 1 + idSize + 4;
183186

184-
if (sizeLong != null) {
185-
size = sizeLong.longValue();
187+
if (sizeLong == null) {
188+
sizeLong = new long[OBJECT_ALIGNMENT+1];
189+
arrayMap.put(cls, sizeLong);
186190
}
187191

188192
int elements = dumpBuffer.getInt(elementsOffset);
189-
int elSize;
190-
191-
if (tag == HprofHeap.PRIMITIVE_ARRAY_DUMP) {
192-
elSize = hprofHeap.getValueSize(dumpBuffer.get(elementsOffset + 4));
193-
} else {
194-
elSize = idSize;
195-
}
196-
197-
size += (getMinimumInstanceSize() + ArrayDump.HPROF_ARRAY_OVERHEAD + (((long)elements) * elSize));
198-
arrayMap.put(cls, Long.valueOf(size));
193+
sizeLong[OBJECT_ALIGNMENT] += elements/OBJECT_ALIGNMENT;
194+
sizeLong[elements%OBJECT_ALIGNMENT]++;
199195
}
200196
}
201197

198+
long alignObjectSize(long size) {
199+
return (size+OBJECT_ALIGNMENT-1) & (~(OBJECT_ALIGNMENT-1));
200+
}
201+
202202
synchronized List<JavaClass> createClassCollection() {
203203
if (classes != null) {
204204
return classes;
@@ -233,6 +233,7 @@ synchronized List<JavaClass> createClassCollection() {
233233
void extractSpecialClasses() {
234234
ClassDump java_lang_Object = null;
235235
primitiveArrayMap = new HashMap();
236+
primitiveTypeMap = new HashMap();
236237

237238
Iterator classIt = classes.iterator();
238239

@@ -285,10 +286,15 @@ void extractSpecialClasses() {
285286

286287
if (typeObj != null) {
287288
primitiveArrayMap.put(typeObj, jcls);
289+
primitiveTypeMap.put(jcls, typeObj);
288290
}
289291
}
290292
if (java_lang_Object != null) {
291-
newSize = java_lang_Object.getRawInstanceSize() > 0;
293+
int objectSize = java_lang_Object.getRawInstanceSize();
294+
if (objectSize > 0) {
295+
newSize = true;
296+
sizeSettings.setMinimumInstanceSize(objectSize);
297+
}
292298
}
293299
}
294300

@@ -303,10 +309,12 @@ void writeToStream(DataOutputStream out) throws IOException {
303309
ClassDump classDump = (ClassDump) classes.get(i);
304310

305311
classDump.writeToStream(out);
306-
Long size = arrayMap.get(classDump);
312+
long[] size = arrayMap.get(classDump);
307313
out.writeBoolean(size != null);
308314
if (size != null) {
309-
out.writeLong(size.longValue());
315+
for (int si=0; si<size.length; si++) {
316+
out.writeLong(size[si]);
317+
}
310318
}
311319
}
312320
}
@@ -323,14 +331,23 @@ void writeToStream(DataOutputStream out) throws IOException {
323331
ClassDump c = new ClassDump(this, dis.readLong(), dis);
324332
cls.add(c);
325333
if (dis.readBoolean()) {
326-
Long size = Long.valueOf(dis.readLong());
334+
long[] size = new long[OBJECT_ALIGNMENT+1];
335+
for (int si = 0; si < size.length; si++) {
336+
size[si] = dis.readLong();
337+
}
327338
arrayMap.put(c, size);
328339
}
329340
}
330341
classes = Collections.unmodifiableList(cls);
331342
}
332343
}
333344

345+
int getArrayElSize(ClassDump cls) {
346+
Integer typeObj = primitiveTypeMap.get(cls);
347+
byte type = typeObj != null ? typeObj.byteValue() : HprofHeap.OBJECT;
348+
return sizeSettings.getElementSize(type);
349+
}
350+
334351
private static class FieldsCache extends LinkedHashMap {
335352
private static final int SIZE = 500;
336353

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/HprofHeap.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class HprofHeap implements Heap {
103103
private static final boolean DEBUG = false;
104104

105105
private static final String SNAPSHOT_ID = "NBPHD";
106-
private static final int SNAPSHOT_VERSION = 3;
106+
private static final int SNAPSHOT_VERSION = 4;
107107
private static final String OS_PROP = "os.name";
108108

109109
//~ Instance fields ----------------------------------------------------------------------------------------------------------
@@ -756,7 +756,7 @@ void computeRetainedSize() {
756756
long origSize = instanceEntry.getRetainedSize();
757757
if (origSize < 0) origSize = 0;
758758
Instance instance = getInstanceByOffset(new long[] {start});
759-
instSize = instance != null ? instance.getSize() : getClassDumpSegment().getMinimumInstanceSize();
759+
instSize = instance != null ? instance.getSize() : getClassDumpSegment().sizeSettings.getMinimumInstanceSize();
760760
instanceEntry.setRetainedSize(origSize + instSize);
761761
}
762762
if (idom != 0) {

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/ObjectArrayDump.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ class ObjectArrayDump extends ArrayDump implements ObjectArrayInstance {
4242
//~ Methods ------------------------------------------------------------------------------------------------------------------
4343

4444
public long getSize() {
45-
long idSize = dumpClass.getHprofBuffer().getIDSize();
46-
47-
return dumpClass.classDumpSegment.getMinimumInstanceSize() + HPROF_ARRAY_OVERHEAD + (idSize * getLength());
45+
return dumpClass.classDumpSegment.getArraySize((byte)HprofHeap.OBJECT, getLength());
4846
}
4947

5048
public List<Instance> getValues() {

0 commit comments

Comments
 (0)