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