1
|
1 |
/*
|
|
2 |
* Copyright 2000-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 |
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 |
* have any questions.
|
|
22 |
*
|
|
23 |
*/
|
|
24 |
|
|
25 |
//
|
|
26 |
// The ObjectHeap is an abstraction over all generations in the VM
|
|
27 |
// It gives access to all present objects and classes.
|
|
28 |
//
|
|
29 |
|
|
30 |
package sun.jvm.hotspot.oops;
|
|
31 |
|
|
32 |
import java.util.*;
|
|
33 |
|
|
34 |
import sun.jvm.hotspot.debugger.*;
|
|
35 |
import sun.jvm.hotspot.gc_interface.*;
|
|
36 |
import sun.jvm.hotspot.gc_implementation.parallelScavenge.*;
|
|
37 |
import sun.jvm.hotspot.memory.*;
|
|
38 |
import sun.jvm.hotspot.runtime.*;
|
|
39 |
import sun.jvm.hotspot.types.*;
|
|
40 |
import sun.jvm.hotspot.utilities.*;
|
|
41 |
|
|
42 |
public class ObjectHeap {
|
|
43 |
|
|
44 |
private OopHandle symbolKlassHandle;
|
|
45 |
private OopHandle methodKlassHandle;
|
|
46 |
private OopHandle constMethodKlassHandle;
|
|
47 |
private OopHandle methodDataKlassHandle;
|
|
48 |
private OopHandle constantPoolKlassHandle;
|
|
49 |
private OopHandle constantPoolCacheKlassHandle;
|
|
50 |
private OopHandle klassKlassHandle;
|
|
51 |
private OopHandle instanceKlassKlassHandle;
|
|
52 |
private OopHandle typeArrayKlassKlassHandle;
|
|
53 |
private OopHandle objArrayKlassKlassHandle;
|
|
54 |
private OopHandle boolArrayKlassHandle;
|
|
55 |
private OopHandle byteArrayKlassHandle;
|
|
56 |
private OopHandle charArrayKlassHandle;
|
|
57 |
private OopHandle intArrayKlassHandle;
|
|
58 |
private OopHandle shortArrayKlassHandle;
|
|
59 |
private OopHandle longArrayKlassHandle;
|
|
60 |
private OopHandle singleArrayKlassHandle;
|
|
61 |
private OopHandle doubleArrayKlassHandle;
|
|
62 |
private OopHandle arrayKlassKlassHandle;
|
|
63 |
private OopHandle compiledICHolderKlassHandle;
|
|
64 |
|
|
65 |
private SymbolKlass symbolKlassObj;
|
|
66 |
private MethodKlass methodKlassObj;
|
|
67 |
private ConstMethodKlass constMethodKlassObj;
|
|
68 |
private MethodDataKlass methodDataKlassObj;
|
|
69 |
private ConstantPoolKlass constantPoolKlassObj;
|
|
70 |
private ConstantPoolCacheKlass constantPoolCacheKlassObj;
|
|
71 |
private KlassKlass klassKlassObj;
|
|
72 |
private InstanceKlassKlass instanceKlassKlassObj;
|
|
73 |
private TypeArrayKlassKlass typeArrayKlassKlassObj;
|
|
74 |
private ObjArrayKlassKlass objArrayKlassKlassObj;
|
|
75 |
private TypeArrayKlass boolArrayKlassObj;
|
|
76 |
private TypeArrayKlass byteArrayKlassObj;
|
|
77 |
private TypeArrayKlass charArrayKlassObj;
|
|
78 |
private TypeArrayKlass intArrayKlassObj;
|
|
79 |
private TypeArrayKlass shortArrayKlassObj;
|
|
80 |
private TypeArrayKlass longArrayKlassObj;
|
|
81 |
private TypeArrayKlass singleArrayKlassObj;
|
|
82 |
private TypeArrayKlass doubleArrayKlassObj;
|
|
83 |
private ArrayKlassKlass arrayKlassKlassObj;
|
|
84 |
private CompiledICHolderKlass compiledICHolderKlassObj;
|
|
85 |
|
|
86 |
public void initialize(TypeDataBase db) throws WrongTypeException {
|
|
87 |
// Lookup the roots in the object hierarchy.
|
|
88 |
Type universeType = db.lookupType("Universe");
|
|
89 |
|
|
90 |
symbolKlassHandle = universeType.getOopField("_symbolKlassObj").getValue();
|
|
91 |
symbolKlassObj = new SymbolKlass(symbolKlassHandle, this);
|
|
92 |
|
|
93 |
methodKlassHandle = universeType.getOopField("_methodKlassObj").getValue();
|
|
94 |
methodKlassObj = new MethodKlass(methodKlassHandle, this);
|
|
95 |
|
|
96 |
constMethodKlassHandle = universeType.getOopField("_constMethodKlassObj").getValue();
|
|
97 |
constMethodKlassObj = new ConstMethodKlass(constMethodKlassHandle, this);
|
|
98 |
|
|
99 |
constantPoolKlassHandle = universeType.getOopField("_constantPoolKlassObj").getValue();
|
|
100 |
constantPoolKlassObj = new ConstantPoolKlass(constantPoolKlassHandle, this);
|
|
101 |
|
|
102 |
constantPoolCacheKlassHandle = universeType.getOopField("_constantPoolCacheKlassObj").getValue();
|
|
103 |
constantPoolCacheKlassObj = new ConstantPoolCacheKlass(constantPoolCacheKlassHandle, this);
|
|
104 |
|
|
105 |
klassKlassHandle = universeType.getOopField("_klassKlassObj").getValue();
|
|
106 |
klassKlassObj = new KlassKlass(klassKlassHandle, this);
|
|
107 |
|
|
108 |
arrayKlassKlassHandle = universeType.getOopField("_arrayKlassKlassObj").getValue();
|
|
109 |
arrayKlassKlassObj = new ArrayKlassKlass(arrayKlassKlassHandle, this);
|
|
110 |
|
|
111 |
instanceKlassKlassHandle = universeType.getOopField("_instanceKlassKlassObj").getValue();
|
|
112 |
instanceKlassKlassObj = new InstanceKlassKlass(instanceKlassKlassHandle, this);
|
|
113 |
|
|
114 |
typeArrayKlassKlassHandle = universeType.getOopField("_typeArrayKlassKlassObj").getValue();
|
|
115 |
typeArrayKlassKlassObj = new TypeArrayKlassKlass(typeArrayKlassKlassHandle, this);
|
|
116 |
|
|
117 |
objArrayKlassKlassHandle = universeType.getOopField("_objArrayKlassKlassObj").getValue();
|
|
118 |
objArrayKlassKlassObj = new ObjArrayKlassKlass(objArrayKlassKlassHandle, this);
|
|
119 |
|
|
120 |
boolArrayKlassHandle = universeType.getOopField("_boolArrayKlassObj").getValue();
|
|
121 |
boolArrayKlassObj = new TypeArrayKlass(boolArrayKlassHandle, this);
|
|
122 |
|
|
123 |
byteArrayKlassHandle = universeType.getOopField("_byteArrayKlassObj").getValue();
|
|
124 |
byteArrayKlassObj = new TypeArrayKlass(byteArrayKlassHandle, this);
|
|
125 |
|
|
126 |
charArrayKlassHandle = universeType.getOopField("_charArrayKlassObj").getValue();
|
|
127 |
charArrayKlassObj = new TypeArrayKlass(charArrayKlassHandle, this);
|
|
128 |
|
|
129 |
intArrayKlassHandle = universeType.getOopField("_intArrayKlassObj").getValue();
|
|
130 |
intArrayKlassObj = new TypeArrayKlass(intArrayKlassHandle, this);
|
|
131 |
|
|
132 |
shortArrayKlassHandle = universeType.getOopField("_shortArrayKlassObj").getValue();
|
|
133 |
shortArrayKlassObj = new TypeArrayKlass(shortArrayKlassHandle, this);
|
|
134 |
|
|
135 |
longArrayKlassHandle = universeType.getOopField("_longArrayKlassObj").getValue();
|
|
136 |
longArrayKlassObj = new TypeArrayKlass(longArrayKlassHandle, this);
|
|
137 |
|
|
138 |
singleArrayKlassHandle = universeType.getOopField("_singleArrayKlassObj").getValue();
|
|
139 |
singleArrayKlassObj = new TypeArrayKlass(singleArrayKlassHandle, this);
|
|
140 |
|
|
141 |
doubleArrayKlassHandle = universeType.getOopField("_doubleArrayKlassObj").getValue();
|
|
142 |
doubleArrayKlassObj = new TypeArrayKlass(doubleArrayKlassHandle, this);
|
|
143 |
|
|
144 |
if (!VM.getVM().isCore()) {
|
|
145 |
methodDataKlassHandle = universeType.getOopField("_methodDataKlassObj").getValue();
|
|
146 |
methodDataKlassObj = new MethodDataKlass(methodDataKlassHandle, this);
|
|
147 |
|
|
148 |
compiledICHolderKlassHandle = universeType.getOopField("_compiledICHolderKlassObj").getValue();
|
|
149 |
compiledICHolderKlassObj= new CompiledICHolderKlass(compiledICHolderKlassHandle ,this);
|
|
150 |
}
|
|
151 |
}
|
|
152 |
|
|
153 |
public ObjectHeap(TypeDataBase db) throws WrongTypeException {
|
|
154 |
// Get commonly used sizes of basic types
|
|
155 |
oopSize = db.getOopSize();
|
|
156 |
byteSize = db.getJByteType().getSize();
|
|
157 |
charSize = db.getJCharType().getSize();
|
|
158 |
booleanSize = db.getJBooleanType().getSize();
|
|
159 |
intSize = db.getJIntType().getSize();
|
|
160 |
shortSize = db.getJShortType().getSize();
|
|
161 |
longSize = db.getJLongType().getSize();
|
|
162 |
floatSize = db.getJFloatType().getSize();
|
|
163 |
doubleSize = db.getJDoubleType().getSize();
|
|
164 |
|
|
165 |
initialize(db);
|
|
166 |
}
|
|
167 |
|
|
168 |
/** Comparison operation for oops, either or both of which may be null */
|
|
169 |
public boolean equal(Oop o1, Oop o2) {
|
|
170 |
if (o1 != null) return o1.equals(o2);
|
|
171 |
return (o2 == null);
|
|
172 |
}
|
|
173 |
|
|
174 |
// Cached sizes of basic types
|
|
175 |
private long oopSize;
|
|
176 |
private long byteSize;
|
|
177 |
private long charSize;
|
|
178 |
private long booleanSize;
|
|
179 |
private long intSize;
|
|
180 |
private long shortSize;
|
|
181 |
private long longSize;
|
|
182 |
private long floatSize;
|
|
183 |
private long doubleSize;
|
|
184 |
|
|
185 |
public long getOopSize() { return oopSize; }
|
|
186 |
public long getByteSize() { return byteSize; }
|
|
187 |
public long getCharSize() { return charSize; }
|
|
188 |
public long getBooleanSize() { return booleanSize; }
|
|
189 |
public long getIntSize() { return intSize; }
|
|
190 |
public long getShortSize() { return shortSize; }
|
|
191 |
public long getLongSize() { return longSize; }
|
|
192 |
public long getFloatSize() { return floatSize; }
|
|
193 |
public long getDoubleSize() { return doubleSize; }
|
|
194 |
|
|
195 |
// Accessors for well-known system classes (from Universe)
|
|
196 |
public SymbolKlass getSymbolKlassObj() { return symbolKlassObj; }
|
|
197 |
public MethodKlass getMethodKlassObj() { return methodKlassObj; }
|
|
198 |
public ConstMethodKlass getConstMethodKlassObj() { return constMethodKlassObj; }
|
|
199 |
public MethodDataKlass getMethodDataKlassObj() { return methodDataKlassObj; }
|
|
200 |
public ConstantPoolKlass getConstantPoolKlassObj() { return constantPoolKlassObj; }
|
|
201 |
public ConstantPoolCacheKlass getConstantPoolCacheKlassObj() { return constantPoolCacheKlassObj; }
|
|
202 |
public KlassKlass getKlassKlassObj() { return klassKlassObj; }
|
|
203 |
public ArrayKlassKlass getArrayKlassKlassObj() { return arrayKlassKlassObj; }
|
|
204 |
public InstanceKlassKlass getInstanceKlassKlassObj() { return instanceKlassKlassObj; }
|
|
205 |
public ObjArrayKlassKlass getObjArrayKlassKlassObj() { return objArrayKlassKlassObj; }
|
|
206 |
public TypeArrayKlassKlass getTypeArrayKlassKlassObj() { return typeArrayKlassKlassObj; }
|
|
207 |
public TypeArrayKlass getBoolArrayKlassObj() { return boolArrayKlassObj; }
|
|
208 |
public TypeArrayKlass getByteArrayKlassObj() { return byteArrayKlassObj; }
|
|
209 |
public TypeArrayKlass getCharArrayKlassObj() { return charArrayKlassObj; }
|
|
210 |
public TypeArrayKlass getIntArrayKlassObj() { return intArrayKlassObj; }
|
|
211 |
public TypeArrayKlass getShortArrayKlassObj() { return shortArrayKlassObj; }
|
|
212 |
public TypeArrayKlass getLongArrayKlassObj() { return longArrayKlassObj; }
|
|
213 |
public TypeArrayKlass getSingleArrayKlassObj() { return singleArrayKlassObj; }
|
|
214 |
public TypeArrayKlass getDoubleArrayKlassObj() { return doubleArrayKlassObj; }
|
|
215 |
public CompiledICHolderKlass getCompiledICHolderKlassObj() {
|
|
216 |
if (Assert.ASSERTS_ENABLED) {
|
|
217 |
Assert.that(!VM.getVM().isCore(), "must not be called for core build");
|
|
218 |
}
|
|
219 |
return compiledICHolderKlassObj;
|
|
220 |
}
|
|
221 |
|
|
222 |
/** Takes a BasicType and returns the corresponding primitive array
|
|
223 |
klass */
|
|
224 |
public Klass typeArrayKlassObj(int t) {
|
|
225 |
if (t == BasicType.getTBoolean()) return getBoolArrayKlassObj();
|
|
226 |
if (t == BasicType.getTChar()) return getCharArrayKlassObj();
|
|
227 |
if (t == BasicType.getTFloat()) return getSingleArrayKlassObj();
|
|
228 |
if (t == BasicType.getTDouble()) return getDoubleArrayKlassObj();
|
|
229 |
if (t == BasicType.getTByte()) return getByteArrayKlassObj();
|
|
230 |
if (t == BasicType.getTShort()) return getShortArrayKlassObj();
|
|
231 |
if (t == BasicType.getTInt()) return getIntArrayKlassObj();
|
|
232 |
if (t == BasicType.getTLong()) return getLongArrayKlassObj();
|
|
233 |
throw new RuntimeException("Illegal basic type " + t);
|
|
234 |
}
|
|
235 |
|
|
236 |
/** an interface to filter objects while walking heap */
|
|
237 |
public static interface ObjectFilter {
|
|
238 |
public boolean canInclude(Oop obj);
|
|
239 |
}
|
|
240 |
|
|
241 |
/** The base heap iteration mechanism */
|
|
242 |
public void iterate(HeapVisitor visitor) {
|
|
243 |
iterateLiveRegions(collectLiveRegions(), visitor, null);
|
|
244 |
}
|
|
245 |
|
|
246 |
/** iterate objects satisfying a specified ObjectFilter */
|
|
247 |
public void iterate(HeapVisitor visitor, ObjectFilter of) {
|
|
248 |
iterateLiveRegions(collectLiveRegions(), visitor, of);
|
|
249 |
}
|
|
250 |
|
|
251 |
/** iterate objects of given Klass. param 'includeSubtypes' tells whether to
|
|
252 |
* include objects of subtypes or not */
|
|
253 |
public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) {
|
|
254 |
if (includeSubtypes) {
|
|
255 |
if (k.isFinal()) {
|
|
256 |
// do the simpler "exact" klass loop
|
|
257 |
iterateExact(visitor, k);
|
|
258 |
} else {
|
|
259 |
iterateSubtypes(visitor, k);
|
|
260 |
}
|
|
261 |
} else {
|
|
262 |
// there can no object of abstract classes and interfaces
|
|
263 |
if (!k.isAbstract() && !k.isInterface()) {
|
|
264 |
iterateExact(visitor, k);
|
|
265 |
}
|
|
266 |
}
|
|
267 |
}
|
|
268 |
|
|
269 |
/** iterate objects of given Klass (objects of subtypes included) */
|
|
270 |
public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) {
|
|
271 |
iterateObjectsOfKlass(visitor, k, true);
|
|
272 |
}
|
|
273 |
|
|
274 |
/** This routine can be used to iterate through the heap at an
|
|
275 |
extremely low level (stepping word-by-word) to provide the
|
|
276 |
ability to do very low-level debugging */
|
|
277 |
public void iterateRaw(RawHeapVisitor visitor) {
|
|
278 |
List liveRegions = collectLiveRegions();
|
|
279 |
|
|
280 |
// Summarize size
|
|
281 |
long totalSize = 0;
|
|
282 |
for (int i = 0; i < liveRegions.size(); i += 2) {
|
|
283 |
Address bottom = (Address) liveRegions.get(i);
|
|
284 |
Address top = (Address) liveRegions.get(i+1);
|
|
285 |
totalSize += top.minus(bottom);
|
|
286 |
}
|
|
287 |
visitor.prologue(totalSize);
|
|
288 |
|
|
289 |
for (int i = 0; i < liveRegions.size(); i += 2) {
|
|
290 |
Address bottom = (Address) liveRegions.get(i);
|
|
291 |
Address top = (Address) liveRegions.get(i+1);
|
|
292 |
|
|
293 |
// Traverses the space from bottom to top
|
|
294 |
while (bottom.lessThan(top)) {
|
|
295 |
visitor.visitAddress(bottom);
|
|
296 |
bottom = bottom.addOffsetTo(VM.getVM().getAddressSize());
|
|
297 |
}
|
|
298 |
}
|
|
299 |
|
|
300 |
visitor.epilogue();
|
|
301 |
}
|
|
302 |
|
|
303 |
// Iterates through only the perm generation for the purpose of
|
|
304 |
// finding static fields for liveness analysis
|
|
305 |
public void iteratePerm(HeapVisitor visitor) {
|
|
306 |
CollectedHeap heap = VM.getVM().getUniverse().heap();
|
|
307 |
List liveRegions = new ArrayList();
|
|
308 |
addPermGenLiveRegions(liveRegions, heap);
|
|
309 |
sortLiveRegions(liveRegions);
|
|
310 |
iterateLiveRegions(liveRegions, visitor, null);
|
|
311 |
}
|
|
312 |
|
|
313 |
// Creates an instance from the Oop hierarchy based based on the handle
|
|
314 |
public Oop newOop(OopHandle handle) {
|
|
315 |
// The only known way to detect the right type of an oop is
|
|
316 |
// traversing the class chain until a well-known klass is recognized.
|
|
317 |
// A more direct solution would require the klasses to expose
|
|
318 |
// the C++ vtbl structure.
|
|
319 |
|
|
320 |
// Handle the null reference
|
|
321 |
if (handle == null) return null;
|
|
322 |
|
|
323 |
// First check if handle is one of the root objects
|
|
324 |
if (handle.equals(methodKlassHandle)) return getMethodKlassObj();
|
|
325 |
if (handle.equals(constMethodKlassHandle)) return getConstMethodKlassObj();
|
|
326 |
if (handle.equals(symbolKlassHandle)) return getSymbolKlassObj();
|
|
327 |
if (handle.equals(constantPoolKlassHandle)) return getConstantPoolKlassObj();
|
|
328 |
if (handle.equals(constantPoolCacheKlassHandle)) return getConstantPoolCacheKlassObj();
|
|
329 |
if (handle.equals(instanceKlassKlassHandle)) return getInstanceKlassKlassObj();
|
|
330 |
if (handle.equals(objArrayKlassKlassHandle)) return getObjArrayKlassKlassObj();
|
|
331 |
if (handle.equals(klassKlassHandle)) return getKlassKlassObj();
|
|
332 |
if (handle.equals(arrayKlassKlassHandle)) return getArrayKlassKlassObj();
|
|
333 |
if (handle.equals(typeArrayKlassKlassHandle)) return getTypeArrayKlassKlassObj();
|
|
334 |
if (handle.equals(boolArrayKlassHandle)) return getBoolArrayKlassObj();
|
|
335 |
if (handle.equals(byteArrayKlassHandle)) return getByteArrayKlassObj();
|
|
336 |
if (handle.equals(charArrayKlassHandle)) return getCharArrayKlassObj();
|
|
337 |
if (handle.equals(intArrayKlassHandle)) return getIntArrayKlassObj();
|
|
338 |
if (handle.equals(shortArrayKlassHandle)) return getShortArrayKlassObj();
|
|
339 |
if (handle.equals(longArrayKlassHandle)) return getLongArrayKlassObj();
|
|
340 |
if (handle.equals(singleArrayKlassHandle)) return getSingleArrayKlassObj();
|
|
341 |
if (handle.equals(doubleArrayKlassHandle)) return getDoubleArrayKlassObj();
|
|
342 |
if (!VM.getVM().isCore()) {
|
|
343 |
if (handle.equals(compiledICHolderKlassHandle)) return getCompiledICHolderKlassObj();
|
|
344 |
if (handle.equals(methodDataKlassHandle)) return getMethodDataKlassObj();
|
|
345 |
}
|
|
346 |
|
|
347 |
// Then check if obj.klass() is one of the root objects
|
|
348 |
OopHandle klass = Oop.getKlassForOopHandle(handle);
|
|
349 |
if (klass != null) {
|
|
350 |
if (klass.equals(methodKlassHandle)) return new Method(handle, this);
|
|
351 |
if (klass.equals(constMethodKlassHandle)) return new ConstMethod(handle, this);
|
|
352 |
if (klass.equals(symbolKlassHandle)) return new Symbol(handle, this);
|
|
353 |
if (klass.equals(constantPoolKlassHandle)) return new ConstantPool(handle, this);
|
|
354 |
if (klass.equals(constantPoolCacheKlassHandle)) return new ConstantPoolCache(handle, this);
|
|
355 |
if (!VM.getVM().isCore()) {
|
|
356 |
if (klass.equals(compiledICHolderKlassHandle)) return new CompiledICHolder(handle, this);
|
|
357 |
if (klass.equals(methodDataKlassHandle)) return new MethodData(handle, this);
|
|
358 |
}
|
|
359 |
if (klass.equals(instanceKlassKlassHandle)) return new InstanceKlass(handle, this);
|
|
360 |
if (klass.equals(objArrayKlassKlassHandle)) return new ObjArrayKlass(handle, this);
|
|
361 |
if (klass.equals(typeArrayKlassKlassHandle)) return new TypeArrayKlass(handle, this);
|
|
362 |
|
|
363 |
// Lastly check if obj.klass().klass() is on of the root objects
|
|
364 |
OopHandle klassKlass = Oop.getKlassForOopHandle(klass);
|
|
365 |
if (klassKlass != null) {
|
|
366 |
if (klassKlass.equals(instanceKlassKlassHandle)) return new Instance(handle, this);
|
|
367 |
if (klassKlass.equals(objArrayKlassKlassHandle)) return new ObjArray(handle, this);
|
|
368 |
if (klassKlass.equals(typeArrayKlassKlassHandle)) return new TypeArray(handle, this);
|
|
369 |
}
|
|
370 |
}
|
|
371 |
|
|
372 |
System.err.println("Unknown oop at " + handle);
|
|
373 |
System.err.println("Oop's klass is " + klass);
|
|
374 |
|
|
375 |
throw new UnknownOopException();
|
|
376 |
}
|
|
377 |
|
|
378 |
// Print all objects in the object heap
|
|
379 |
public void print() {
|
|
380 |
HeapPrinter printer = new HeapPrinter(System.out);
|
|
381 |
iterate(printer);
|
|
382 |
}
|
|
383 |
|
|
384 |
//---------------------------------------------------------------------------
|
|
385 |
// Internals only below this point
|
|
386 |
//
|
|
387 |
|
|
388 |
private void iterateExact(HeapVisitor visitor, final Klass k) {
|
|
389 |
iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() {
|
|
390 |
public boolean canInclude(Oop obj) {
|
|
391 |
Klass tk = obj.getKlass();
|
|
392 |
// null Klass is seen sometimes!
|
|
393 |
return (tk != null && tk.equals(k));
|
|
394 |
}
|
|
395 |
});
|
|
396 |
}
|
|
397 |
|
|
398 |
private void iterateSubtypes(HeapVisitor visitor, final Klass k) {
|
|
399 |
iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() {
|
|
400 |
public boolean canInclude(Oop obj) {
|
|
401 |
Klass tk = obj.getKlass();
|
|
402 |
// null Klass is seen sometimes!
|
|
403 |
return (tk != null && tk.isSubtypeOf(k));
|
|
404 |
}
|
|
405 |
});
|
|
406 |
}
|
|
407 |
|
|
408 |
private void iterateLiveRegions(List liveRegions, HeapVisitor visitor, ObjectFilter of) {
|
|
409 |
// Summarize size
|
|
410 |
long totalSize = 0;
|
|
411 |
for (int i = 0; i < liveRegions.size(); i += 2) {
|
|
412 |
Address bottom = (Address) liveRegions.get(i);
|
|
413 |
Address top = (Address) liveRegions.get(i+1);
|
|
414 |
totalSize += top.minus(bottom);
|
|
415 |
}
|
|
416 |
visitor.prologue(totalSize);
|
|
417 |
|
|
418 |
CompactibleFreeListSpace cmsSpaceOld = null;
|
|
419 |
CompactibleFreeListSpace cmsSpacePerm = null;
|
|
420 |
CollectedHeap heap = VM.getVM().getUniverse().heap();
|
|
421 |
|
|
422 |
if (heap instanceof GenCollectedHeap) {
|
|
423 |
GenCollectedHeap genHeap = (GenCollectedHeap) heap;
|
|
424 |
Generation genOld = genHeap.getGen(1);
|
|
425 |
Generation genPerm = genHeap.permGen();
|
|
426 |
if (genOld instanceof ConcurrentMarkSweepGeneration) {
|
|
427 |
ConcurrentMarkSweepGeneration concGen = (ConcurrentMarkSweepGeneration)genOld;
|
|
428 |
cmsSpaceOld = concGen.cmsSpace();
|
|
429 |
}
|
|
430 |
if (genPerm instanceof ConcurrentMarkSweepGeneration) {
|
|
431 |
ConcurrentMarkSweepGeneration concGen = (ConcurrentMarkSweepGeneration)genPerm;
|
|
432 |
cmsSpacePerm = concGen.cmsSpace();
|
|
433 |
}
|
|
434 |
}
|
|
435 |
|
|
436 |
for (int i = 0; i < liveRegions.size(); i += 2) {
|
|
437 |
Address bottom = (Address) liveRegions.get(i);
|
|
438 |
Address top = (Address) liveRegions.get(i+1);
|
|
439 |
|
|
440 |
try {
|
|
441 |
// Traverses the space from bottom to top
|
|
442 |
OopHandle handle = bottom.addOffsetToAsOopHandle(0);
|
|
443 |
while (handle.lessThan(top)) {
|
|
444 |
Oop obj = null;
|
|
445 |
|
|
446 |
try {
|
|
447 |
obj = newOop(handle);
|
|
448 |
} catch (UnknownOopException exp) {
|
|
449 |
}
|
|
450 |
if (obj == null) {
|
|
451 |
//Find the object size using Printezis bits and skip over
|
|
452 |
System.err.println("Finding object size using Printezis bits and skipping over...");
|
|
453 |
long size = 0;
|
|
454 |
|
|
455 |
if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) ){
|
|
456 |
size = cmsSpaceOld.collector().blockSizeUsingPrintezisBits(handle);
|
|
457 |
} else if ((cmsSpacePerm != null) && cmsSpacePerm.contains(handle) ){
|
|
458 |
size = cmsSpacePerm.collector().blockSizeUsingPrintezisBits(handle);
|
|
459 |
}
|
|
460 |
|
|
461 |
if (size <= 0) {
|
|
462 |
//Either Printezis bits not set or handle is not in cms space.
|
|
463 |
throw new UnknownOopException();
|
|
464 |
}
|
|
465 |
|
|
466 |
handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(size));
|
|
467 |
continue;
|
|
468 |
}
|
|
469 |
if (of == null || of.canInclude(obj)) {
|
|
470 |
if (visitor.doObj(obj)) {
|
|
471 |
// doObj() returns true to abort this loop.
|
|
472 |
break;
|
|
473 |
}
|
|
474 |
}
|
|
475 |
if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) ||
|
|
476 |
(cmsSpacePerm != null) && cmsSpacePerm.contains(handle) ) {
|
|
477 |
handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(obj.getObjectSize()) );
|
|
478 |
} else {
|
|
479 |
handle = handle.addOffsetToAsOopHandle(obj.getObjectSize());
|
|
480 |
}
|
|
481 |
}
|
|
482 |
}
|
|
483 |
catch (AddressException e) {
|
|
484 |
// This is okay at the top of these regions
|
|
485 |
}
|
|
486 |
catch (UnknownOopException e) {
|
|
487 |
// This is okay at the top of these regions
|
|
488 |
}
|
|
489 |
}
|
|
490 |
|
|
491 |
visitor.epilogue();
|
|
492 |
}
|
|
493 |
|
|
494 |
private void addPermGenLiveRegions(List output, CollectedHeap heap) {
|
|
495 |
LiveRegionsCollector lrc = new LiveRegionsCollector(output);
|
|
496 |
if (heap instanceof GenCollectedHeap) {
|
|
497 |
GenCollectedHeap genHeap = (GenCollectedHeap) heap;
|
|
498 |
Generation gen = genHeap.permGen();
|
|
499 |
gen.spaceIterate(lrc, true);
|
|
500 |
} else if (heap instanceof ParallelScavengeHeap) {
|
|
501 |
ParallelScavengeHeap psh = (ParallelScavengeHeap) heap;
|
|
502 |
PSPermGen permGen = psh.permGen();
|
|
503 |
addLiveRegions(permGen.objectSpace().getLiveRegions(), output);
|
|
504 |
} else {
|
|
505 |
if (Assert.ASSERTS_ENABLED) {
|
|
506 |
Assert.that(false, "Expecting GenCollectedHeap or ParallelScavengeHeap, but got " +
|
|
507 |
heap.getClass().getName());
|
|
508 |
}
|
|
509 |
}
|
|
510 |
}
|
|
511 |
|
|
512 |
private void addLiveRegions(List input, List output) {
|
|
513 |
for (Iterator itr = input.iterator(); itr.hasNext();) {
|
|
514 |
MemRegion reg = (MemRegion) itr.next();
|
|
515 |
Address top = reg.end();
|
|
516 |
Address bottom = reg.start();
|
|
517 |
if (Assert.ASSERTS_ENABLED) {
|
|
518 |
Assert.that(top != null, "top address in a live region should not be null");
|
|
519 |
}
|
|
520 |
if (Assert.ASSERTS_ENABLED) {
|
|
521 |
Assert.that(bottom != null, "bottom address in a live region should not be null");
|
|
522 |
}
|
|
523 |
output.add(top);
|
|
524 |
output.add(bottom);
|
|
525 |
}
|
|
526 |
}
|
|
527 |
|
|
528 |
private class LiveRegionsCollector implements SpaceClosure {
|
|
529 |
LiveRegionsCollector(List l) {
|
|
530 |
liveRegions = l;
|
|
531 |
}
|
|
532 |
|
|
533 |
public void doSpace(Space s) {
|
|
534 |
addLiveRegions(s.getLiveRegions(), liveRegions);
|
|
535 |
}
|
|
536 |
private List liveRegions;
|
|
537 |
}
|
|
538 |
|
|
539 |
// Returns a List<Address> where the addresses come in pairs. These
|
|
540 |
// designate the live regions of the heap.
|
|
541 |
private List collectLiveRegions() {
|
|
542 |
// We want to iterate through all live portions of the heap, but
|
|
543 |
// do not want to abort the heap traversal prematurely if we find
|
|
544 |
// a problem (like an allocated but uninitialized object at the
|
|
545 |
// top of a generation). To do this we enumerate all generations'
|
|
546 |
// bottom and top regions, and factor in TLABs if necessary.
|
|
547 |
|
|
548 |
// List<Address>. Addresses come in pairs.
|
|
549 |
List liveRegions = new ArrayList();
|
|
550 |
LiveRegionsCollector lrc = new LiveRegionsCollector(liveRegions);
|
|
551 |
|
|
552 |
CollectedHeap heap = VM.getVM().getUniverse().heap();
|
|
553 |
|
|
554 |
if (heap instanceof GenCollectedHeap) {
|
|
555 |
GenCollectedHeap genHeap = (GenCollectedHeap) heap;
|
|
556 |
// Run through all generations, obtaining bottom-top pairs.
|
|
557 |
for (int i = 0; i < genHeap.nGens(); i++) {
|
|
558 |
Generation gen = genHeap.getGen(i);
|
|
559 |
gen.spaceIterate(lrc, true);
|
|
560 |
}
|
|
561 |
} else if (heap instanceof ParallelScavengeHeap) {
|
|
562 |
ParallelScavengeHeap psh = (ParallelScavengeHeap) heap;
|
|
563 |
PSYoungGen youngGen = psh.youngGen();
|
|
564 |
// Add eden space
|
|
565 |
addLiveRegions(youngGen.edenSpace().getLiveRegions(), liveRegions);
|
|
566 |
// Add from-space but not to-space
|
|
567 |
addLiveRegions(youngGen.fromSpace().getLiveRegions(), liveRegions);
|
|
568 |
PSOldGen oldGen = psh.oldGen();
|
|
569 |
addLiveRegions(oldGen.objectSpace().getLiveRegions(), liveRegions);
|
|
570 |
} else {
|
|
571 |
if (Assert.ASSERTS_ENABLED) {
|
|
572 |
Assert.that(false, "Expecting GenCollectedHeap or ParallelScavengeHeap, but got " +
|
|
573 |
heap.getClass().getName());
|
|
574 |
}
|
|
575 |
}
|
|
576 |
|
|
577 |
// handle perm generation
|
|
578 |
addPermGenLiveRegions(liveRegions, heap);
|
|
579 |
|
|
580 |
// If UseTLAB is enabled, snip out regions associated with TLABs'
|
|
581 |
// dead regions. Note that TLABs can be present in any generation.
|
|
582 |
|
|
583 |
// FIXME: consider adding fewer boundaries to live region list.
|
|
584 |
// Theoretically only need to stop at TLAB's top and resume at its
|
|
585 |
// end.
|
|
586 |
|
|
587 |
if (VM.getVM().getUseTLAB()) {
|
|
588 |
for (JavaThread thread = VM.getVM().getThreads().first(); thread != null; thread = thread.next()) {
|
|
589 |
if (thread.isJavaThread()) {
|
|
590 |
ThreadLocalAllocBuffer tlab = thread.tlab();
|
|
591 |
if (tlab.start() != null) {
|
|
592 |
if ((tlab.top() == null) || (tlab.end() == null)) {
|
|
593 |
System.err.print("Warning: skipping invalid TLAB for thread ");
|
|
594 |
thread.printThreadIDOn(System.err);
|
|
595 |
System.err.println();
|
|
596 |
} else {
|
|
597 |
// Go from:
|
|
598 |
// - below start() to start()
|
|
599 |
// - start() to top()
|
|
600 |
// - end() and above
|
|
601 |
liveRegions.add(tlab.start());
|
|
602 |
liveRegions.add(tlab.start());
|
|
603 |
liveRegions.add(tlab.top());
|
|
604 |
liveRegions.add(tlab.end());
|
|
605 |
}
|
|
606 |
}
|
|
607 |
}
|
|
608 |
}
|
|
609 |
}
|
|
610 |
|
|
611 |
// Now sort live regions
|
|
612 |
sortLiveRegions(liveRegions);
|
|
613 |
|
|
614 |
if (Assert.ASSERTS_ENABLED) {
|
|
615 |
Assert.that(liveRegions.size() % 2 == 0, "Must have even number of region boundaries");
|
|
616 |
}
|
|
617 |
|
|
618 |
return liveRegions;
|
|
619 |
}
|
|
620 |
|
|
621 |
private void sortLiveRegions(List liveRegions) {
|
|
622 |
Collections.sort(liveRegions, new Comparator() {
|
|
623 |
public int compare(Object o1, Object o2) {
|
|
624 |
Address a1 = (Address) o1;
|
|
625 |
Address a2 = (Address) o2;
|
|
626 |
if (AddressOps.lt(a1, a2)) {
|
|
627 |
return -1;
|
|
628 |
} else if (AddressOps.gt(a1, a2)) {
|
|
629 |
return 1;
|
|
630 |
}
|
|
631 |
return 0;
|
|
632 |
}
|
|
633 |
});
|
|
634 |
}
|
|
635 |
}
|