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