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