1 /* 2 * Copyright (c) 2000, 2015, 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 // 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.shared.*; 36 import sun.jvm.hotspot.gc.g1.*; 37 import sun.jvm.hotspot.gc.parallel.*; 38 import sun.jvm.hotspot.memory.*; 39 import sun.jvm.hotspot.runtime.*; 40 import sun.jvm.hotspot.types.*; 41 import sun.jvm.hotspot.utilities.*; 42 43 public class ObjectHeap { 44 45 private static final boolean DEBUG; 46 47 static { 48 DEBUG = System.getProperty("sun.jvm.hotspot.oops.ObjectHeap.DEBUG") != null; 49 } 50 51 private Address boolArrayKlassHandle; 52 private Address byteArrayKlassHandle; 53 private Address charArrayKlassHandle; 54 private Address intArrayKlassHandle; 55 private Address shortArrayKlassHandle; 56 private Address longArrayKlassHandle; 57 private Address singleArrayKlassHandle; 58 private Address doubleArrayKlassHandle; 59 60 private TypeArrayKlass boolArrayKlassObj; 61 private TypeArrayKlass byteArrayKlassObj; 62 private TypeArrayKlass charArrayKlassObj; 63 private TypeArrayKlass intArrayKlassObj; 64 private TypeArrayKlass shortArrayKlassObj; 65 private TypeArrayKlass longArrayKlassObj; 66 private TypeArrayKlass singleArrayKlassObj; 67 private TypeArrayKlass doubleArrayKlassObj; 68 69 public void initialize(TypeDataBase db) throws WrongTypeException { 70 // Lookup the roots in the object hierarchy. 71 Type universeType = db.lookupType("Universe"); 72 73 boolArrayKlassHandle = universeType.getAddressField("_boolArrayKlassObj").getValue(); 74 boolArrayKlassObj = new TypeArrayKlass(boolArrayKlassHandle); 75 76 byteArrayKlassHandle = universeType.getAddressField("_byteArrayKlassObj").getValue(); 77 byteArrayKlassObj = new TypeArrayKlass(byteArrayKlassHandle); 78 79 charArrayKlassHandle = universeType.getAddressField("_charArrayKlassObj").getValue(); 80 charArrayKlassObj = new TypeArrayKlass(charArrayKlassHandle); 81 82 intArrayKlassHandle = universeType.getAddressField("_intArrayKlassObj").getValue(); 83 intArrayKlassObj = new TypeArrayKlass(intArrayKlassHandle); 84 85 shortArrayKlassHandle = universeType.getAddressField("_shortArrayKlassObj").getValue(); 86 shortArrayKlassObj = new TypeArrayKlass(shortArrayKlassHandle); 87 88 longArrayKlassHandle = universeType.getAddressField("_longArrayKlassObj").getValue(); 89 longArrayKlassObj = new TypeArrayKlass(longArrayKlassHandle); 90 91 singleArrayKlassHandle = universeType.getAddressField("_singleArrayKlassObj").getValue(); 92 singleArrayKlassObj = new TypeArrayKlass(singleArrayKlassHandle); 93 94 doubleArrayKlassHandle = universeType.getAddressField("_doubleArrayKlassObj").getValue(); 95 doubleArrayKlassObj = new TypeArrayKlass(doubleArrayKlassHandle); 96 } 97 98 public ObjectHeap(TypeDataBase db) throws WrongTypeException { 99 // Get commonly used sizes of basic types 100 oopSize = VM.getVM().getOopSize(); 101 byteSize = db.getJByteType().getSize(); 102 charSize = db.getJCharType().getSize(); 103 booleanSize = db.getJBooleanType().getSize(); 104 intSize = db.getJIntType().getSize(); 105 shortSize = db.getJShortType().getSize(); 106 longSize = db.getJLongType().getSize(); 107 floatSize = db.getJFloatType().getSize(); 108 doubleSize = db.getJDoubleType().getSize(); 109 110 initialize(db); 111 } 112 113 /** Comparison operation for oops, either or both of which may be null */ 114 public boolean equal(Oop o1, Oop o2) { 115 if (o1 != null) return o1.equals(o2); 116 return (o2 == null); 117 } 118 119 // Cached sizes of basic types 120 private long oopSize; 121 private long byteSize; 122 private long charSize; 123 private long booleanSize; 124 private long intSize; 125 private long shortSize; 126 private long longSize; 127 private long floatSize; 128 private long doubleSize; 129 130 public long getOopSize() { return oopSize; } 131 public long getByteSize() { return byteSize; } 132 public long getCharSize() { return charSize; } 133 public long getBooleanSize() { return booleanSize; } 134 public long getIntSize() { return intSize; } 135 public long getShortSize() { return shortSize; } 136 public long getLongSize() { return longSize; } 137 public long getFloatSize() { return floatSize; } 138 public long getDoubleSize() { return doubleSize; } 139 140 // Accessors for well-known system classes (from Universe) 141 public TypeArrayKlass getBoolArrayKlassObj() { return boolArrayKlassObj; } 142 public TypeArrayKlass getByteArrayKlassObj() { return byteArrayKlassObj; } 143 public TypeArrayKlass getCharArrayKlassObj() { return charArrayKlassObj; } 144 public TypeArrayKlass getIntArrayKlassObj() { return intArrayKlassObj; } 145 public TypeArrayKlass getShortArrayKlassObj() { return shortArrayKlassObj; } 146 public TypeArrayKlass getLongArrayKlassObj() { return longArrayKlassObj; } 147 public TypeArrayKlass getSingleArrayKlassObj() { return singleArrayKlassObj; } 148 public TypeArrayKlass getDoubleArrayKlassObj() { return doubleArrayKlassObj; } 149 150 /** Takes a BasicType and returns the corresponding primitive array 151 klass */ 152 public Klass typeArrayKlassObj(int t) { 153 if (t == BasicType.getTBoolean()) return getBoolArrayKlassObj(); 154 if (t == BasicType.getTChar()) return getCharArrayKlassObj(); 155 if (t == BasicType.getTFloat()) return getSingleArrayKlassObj(); 156 if (t == BasicType.getTDouble()) return getDoubleArrayKlassObj(); 157 if (t == BasicType.getTByte()) return getByteArrayKlassObj(); 158 if (t == BasicType.getTShort()) return getShortArrayKlassObj(); 159 if (t == BasicType.getTInt()) return getIntArrayKlassObj(); 160 if (t == BasicType.getTLong()) return getLongArrayKlassObj(); 161 throw new RuntimeException("Illegal basic type " + t); 162 } 163 164 /** an interface to filter objects while walking heap */ 165 public static interface ObjectFilter { 166 public boolean canInclude(Oop obj); 167 } 168 169 /** The base heap iteration mechanism */ 170 public void iterate(HeapVisitor visitor) { 171 iterateLiveRegions(collectLiveRegions(), visitor, null); 172 } 173 174 /** iterate objects satisfying a specified ObjectFilter */ 175 public void iterate(HeapVisitor visitor, ObjectFilter of) { 176 iterateLiveRegions(collectLiveRegions(), visitor, of); 177 } 178 179 /** iterate objects of given Klass. param 'includeSubtypes' tells whether to 180 * include objects of subtypes or not */ 181 public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) { 182 if (includeSubtypes) { 183 if (k.isFinal()) { 184 // do the simpler "exact" klass loop 185 iterateExact(visitor, k); 186 } else { 187 iterateSubtypes(visitor, k); 188 } 189 } else { 190 // there can no object of abstract classes and interfaces 191 if (!k.isAbstract() && !k.isInterface()) { 192 iterateExact(visitor, k); 193 } 194 } 195 } 196 197 /** iterate objects of given Klass (objects of subtypes included) */ 198 public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) { 199 iterateObjectsOfKlass(visitor, k, true); 200 } 201 202 /** This routine can be used to iterate through the heap at an 203 extremely low level (stepping word-by-word) to provide the 204 ability to do very low-level debugging */ 205 public void iterateRaw(RawHeapVisitor visitor) { 206 List liveRegions = collectLiveRegions(); 207 208 // Summarize size 209 long totalSize = 0; 210 for (int i = 0; i < liveRegions.size(); i += 2) { 211 Address bottom = (Address) liveRegions.get(i); 212 Address top = (Address) liveRegions.get(i+1); 213 totalSize += top.minus(bottom); 214 } 215 visitor.prologue(totalSize); 216 217 for (int i = 0; i < liveRegions.size(); i += 2) { 218 Address bottom = (Address) liveRegions.get(i); 219 Address top = (Address) liveRegions.get(i+1); 220 221 // Traverses the space from bottom to top 222 while (bottom.lessThan(top)) { 223 visitor.visitAddress(bottom); 224 bottom = bottom.addOffsetTo(VM.getVM().getAddressSize()); 225 } 226 } 227 228 visitor.epilogue(); 229 } 230 231 public boolean isValidMethod(Address handle) { 232 try { 233 Method m = (Method)Metadata.instantiateWrapperFor(handle); 234 return true; 235 } catch (Exception e) { 236 return false; 237 } 238 } 239 240 // Creates an instance from the Oop hierarchy based based on the handle 241 public Oop newOop(OopHandle handle) { 242 // The only known way to detect the right type of an oop is 243 // traversing the class chain until a well-known klass is recognized. 244 // A more direct solution would require the klasses to expose 245 // the C++ vtbl structure. 246 247 // Handle the null reference 248 if (handle == null) return null; 249 250 // Then check if obj.klass() is one of the root objects 251 Klass klass = Oop.getKlassForOopHandle(handle); 252 if (klass != null) { 253 if (klass instanceof TypeArrayKlass) return new TypeArray(handle, this); 254 if (klass instanceof ObjArrayKlass) return new ObjArray(handle, this); 255 if (klass instanceof InstanceKlass) return new Instance(handle, this); 256 } 257 258 if (DEBUG) { 259 System.err.println("Unknown oop at " + handle); 260 System.err.println("Oop's klass is " + klass); 261 } 262 263 throw new UnknownOopException(); 264 } 265 266 // Print all objects in the object heap 267 public void print() { 268 HeapPrinter printer = new HeapPrinter(System.out); 269 iterate(printer); 270 } 271 272 //--------------------------------------------------------------------------- 273 // Internals only below this point 274 // 275 276 private void iterateExact(HeapVisitor visitor, final Klass k) { 277 iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() { 278 public boolean canInclude(Oop obj) { 279 Klass tk = obj.getKlass(); 280 // null Klass is seen sometimes! 281 return (tk != null && tk.equals(k)); 282 } 283 }); 284 } 285 286 private void iterateSubtypes(HeapVisitor visitor, final Klass k) { 287 iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() { 288 public boolean canInclude(Oop obj) { 289 Klass tk = obj.getKlass(); 290 // null Klass is seen sometimes! 291 return (tk != null && tk.isSubtypeOf(k)); 292 } 293 }); 294 } 295 296 private void iterateLiveRegions(List liveRegions, HeapVisitor visitor, ObjectFilter of) { 297 // Summarize size 298 long totalSize = 0; 299 for (int i = 0; i < liveRegions.size(); i += 2) { 300 Address bottom = (Address) liveRegions.get(i); 301 Address top = (Address) liveRegions.get(i+1); 302 totalSize += top.minus(bottom); 303 } 304 visitor.prologue(totalSize); 305 306 CompactibleFreeListSpace cmsSpaceOld = null; 307 CollectedHeap heap = VM.getVM().getUniverse().heap(); 308 309 if (heap instanceof GenCollectedHeap) { 310 GenCollectedHeap genHeap = (GenCollectedHeap) heap; 311 Generation genOld = genHeap.getGen(1); 312 if (genOld instanceof ConcurrentMarkSweepGeneration) { 313 ConcurrentMarkSweepGeneration concGen = (ConcurrentMarkSweepGeneration)genOld; 314 cmsSpaceOld = concGen.cmsSpace(); 315 } 316 } 317 318 for (int i = 0; i < liveRegions.size(); i += 2) { 319 Address bottom = (Address) liveRegions.get(i); 320 Address top = (Address) liveRegions.get(i+1); 321 322 try { 323 // Traverses the space from bottom to top 324 OopHandle handle = bottom.addOffsetToAsOopHandle(0); 325 326 while (handle.lessThan(top)) { 327 Oop obj = null; 328 329 try { 330 obj = newOop(handle); 331 } catch (UnknownOopException exp) { 332 if (DEBUG) { 333 throw new RuntimeException(" UnknownOopException " + exp); 334 } 335 } 336 if (obj == null) { 337 //Find the object size using Printezis bits and skip over 338 long size = 0; 339 340 if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) ){ 341 size = cmsSpaceOld.collector().blockSizeUsingPrintezisBits(handle); 342 } 343 344 if (size <= 0) { 345 //Either Printezis bits not set or handle is not in cms space. 346 throw new UnknownOopException(); 347 } 348 349 handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(size)); 350 continue; 351 } 352 if (of == null || of.canInclude(obj)) { 353 if (visitor.doObj(obj)) { 354 // doObj() returns true to abort this loop. 355 break; 356 } 357 } 358 if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle)) { 359 handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(obj.getObjectSize()) ); 360 } else { 361 handle = handle.addOffsetToAsOopHandle(obj.getObjectSize()); 362 } 363 } 364 } 365 catch (AddressException e) { 366 // This is okay at the top of these regions 367 } 368 catch (UnknownOopException e) { 369 // This is okay at the top of these regions 370 } 371 } 372 373 visitor.epilogue(); 374 } 375 376 private void addLiveRegions(String name, List input, List output) { 377 for (Iterator itr = input.iterator(); itr.hasNext();) { 378 MemRegion reg = (MemRegion) itr.next(); 379 Address top = reg.end(); 380 Address bottom = reg.start(); 381 if (Assert.ASSERTS_ENABLED) { 382 Assert.that(top != null, "top address in a live region should not be null"); 383 } 384 if (Assert.ASSERTS_ENABLED) { 385 Assert.that(bottom != null, "bottom address in a live region should not be null"); 386 } 387 output.add(top); 388 output.add(bottom); 389 if (DEBUG) { 390 System.err.println("Live region: " + name + ": " + bottom + ", " + top); 391 } 392 } 393 } 394 395 private class LiveRegionsCollector implements SpaceClosure { 396 LiveRegionsCollector(List l) { 397 liveRegions = l; 398 } 399 400 public void doSpace(Space s) { 401 addLiveRegions(s.toString(), s.getLiveRegions(), liveRegions); 402 } 403 private List liveRegions; 404 } 405 406 // Returns a List<Address> where the addresses come in pairs. These 407 // designate the live regions of the heap. 408 private List collectLiveRegions() { 409 // We want to iterate through all live portions of the heap, but 410 // do not want to abort the heap traversal prematurely if we find 411 // a problem (like an allocated but uninitialized object at the 412 // top of a generation). To do this we enumerate all generations' 413 // bottom and top regions, and factor in TLABs if necessary. 414 415 // List<Address>. Addresses come in pairs. 416 List liveRegions = new ArrayList(); 417 LiveRegionsCollector lrc = new LiveRegionsCollector(liveRegions); 418 419 CollectedHeap heap = VM.getVM().getUniverse().heap(); 420 421 if (heap instanceof GenCollectedHeap) { 422 GenCollectedHeap genHeap = (GenCollectedHeap) heap; 423 // Run through all generations, obtaining bottom-top pairs. 424 for (int i = 0; i < genHeap.nGens(); i++) { 425 Generation gen = genHeap.getGen(i); 426 gen.spaceIterate(lrc, true); 427 } 428 } else if (heap instanceof ParallelScavengeHeap) { 429 ParallelScavengeHeap psh = (ParallelScavengeHeap) heap; 430 PSYoungGen youngGen = psh.youngGen(); 431 // Add eden space 432 addLiveRegions("eden", youngGen.edenSpace().getLiveRegions(), liveRegions); 433 // Add from-space but not to-space 434 addLiveRegions("from", youngGen.fromSpace().getLiveRegions(), liveRegions); 435 PSOldGen oldGen = psh.oldGen(); 436 addLiveRegions("old ", oldGen.objectSpace().getLiveRegions(), liveRegions); 437 } else if (heap instanceof G1CollectedHeap) { 438 G1CollectedHeap g1h = (G1CollectedHeap) heap; 439 g1h.heapRegionIterate(lrc); 440 } else { 441 if (Assert.ASSERTS_ENABLED) { 442 Assert.that(false, "Expecting GenCollectedHeap, G1CollectedHeap, " + 443 "or ParallelScavengeHeap, but got " + 444 heap.getClass().getName()); 445 } 446 } 447 448 // If UseTLAB is enabled, snip out regions associated with TLABs' 449 // dead regions. Note that TLABs can be present in any generation. 450 451 // FIXME: consider adding fewer boundaries to live region list. 452 // Theoretically only need to stop at TLAB's top and resume at its 453 // end. 454 455 if (VM.getVM().getUseTLAB()) { 456 for (JavaThread thread = VM.getVM().getThreads().first(); thread != null; thread = thread.next()) { 457 ThreadLocalAllocBuffer tlab = thread.tlab(); 458 if (tlab.start() != null) { 459 if ((tlab.top() == null) || (tlab.end() == null)) { 460 System.err.print("Warning: skipping invalid TLAB for thread "); 461 thread.printThreadIDOn(System.err); 462 System.err.println(); 463 } else { 464 if (DEBUG) { 465 System.err.print("TLAB for " + thread.getThreadName() + ", #"); 466 thread.printThreadIDOn(System.err); 467 System.err.print(": "); 468 tlab.printOn(System.err); 469 } 470 // Go from: 471 // - below start() to start() 472 // - start() to top() 473 // - end() and above 474 liveRegions.add(tlab.start()); 475 liveRegions.add(tlab.start()); 476 liveRegions.add(tlab.top()); 477 liveRegions.add(tlab.hardEnd()); 478 } 479 } 480 } 481 } 482 483 // Now sort live regions 484 sortLiveRegions(liveRegions); 485 486 if (Assert.ASSERTS_ENABLED) { 487 Assert.that(liveRegions.size() % 2 == 0, "Must have even number of region boundaries"); 488 } 489 490 if (DEBUG) { 491 System.err.println("liveRegions:"); 492 for (int i = 0; i < liveRegions.size(); i += 2) { 493 Address bottom = (Address) liveRegions.get(i); 494 Address top = (Address) liveRegions.get(i+1); 495 System.err.println(" " + bottom + " - " + top); 496 } 497 } 498 499 return liveRegions; 500 } 501 502 private void sortLiveRegions(List liveRegions) { 503 Collections.sort(liveRegions, new Comparator() { 504 public int compare(Object o1, Object o2) { 505 Address a1 = (Address) o1; 506 Address a2 = (Address) o2; 507 if (AddressOps.lt(a1, a2)) { 508 return -1; 509 } else if (AddressOps.gt(a1, a2)) { 510 return 1; 511 } 512 return 0; 513 } 514 }); 515 } 516 }