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