1 /* 2 * Copyright (c) 2003, 2019, 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 package sun.jvm.hotspot.gc.cms; 26 27 import java.io.*; 28 import java.util.*; 29 30 import sun.jvm.hotspot.debugger.*; 31 import sun.jvm.hotspot.gc.shared.*; 32 import sun.jvm.hotspot.memory.*; 33 import sun.jvm.hotspot.oops.*; 34 import sun.jvm.hotspot.runtime.*; 35 import sun.jvm.hotspot.types.*; 36 import sun.jvm.hotspot.utilities.*; 37 38 public class CompactibleFreeListSpace extends CompactibleSpace implements LiveRegionsProvider { 39 private static AddressField collectorField; 40 private static AddressField indexedFreeListField; 41 private static AddressField dictionaryField; 42 private static long smallLinearAllocBlockFieldOffset; 43 44 private int heapWordSize; // 4 for 32bit, 8 for 64 bits 45 private int IndexSetStart; // for small indexed list 46 private int IndexSetSize; 47 private int IndexSetStride; 48 private static long MinChunkSizeInBytes; 49 50 static { 51 VM.registerVMInitializedObserver(new Observer() { 52 public void update(Observable o, Object data) { 53 initialize(VM.getVM().getTypeDataBase()); 54 } 55 }); 56 } 57 58 private static synchronized void initialize(TypeDataBase db) { 59 long sizeofFreeChunk = db.lookupType("FreeChunk").getSize(); 60 VM vm = VM.getVM(); 61 62 Type type = db.lookupType("CompactibleFreeListSpace"); 63 collectorField = type.getAddressField("_collector"); 64 collectorField = type.getAddressField("_collector"); 65 dictionaryField = type.getAddressField("_dictionary"); 66 indexedFreeListField = type.getAddressField("_indexedFreeList[0]"); 67 smallLinearAllocBlockFieldOffset = type.getField("_smallLinearAllocBlock").getOffset(); 68 MinChunkSizeInBytes = (type.getCIntegerField("_min_chunk_size_in_bytes")).getValue(); 69 } 70 71 public CompactibleFreeListSpace(Address addr) { 72 super(addr); 73 VM vm = VM.getVM(); 74 heapWordSize = vm.getHeapWordSize(); 75 IndexSetStart = vm.getMinObjAlignmentInBytes() / heapWordSize; 76 IndexSetStride = IndexSetStart; 77 IndexSetSize = vm.getIndexSetSize(); 78 } 79 80 // Accessing block offset table 81 public CMSCollector collector() { 82 return (CMSCollector) VMObjectFactory.newObject( 83 CMSCollector.class, 84 collectorField.getValue(addr)); 85 } 86 87 public long free0() { 88 return capacity() - used0(); 89 } 90 91 public long used() { 92 return capacity() - free(); 93 } 94 95 public long used0() { 96 List<MemRegion> regions = getLiveRegions(); 97 long usedSize = 0L; 98 for (Iterator<MemRegion> itr = regions.iterator(); itr.hasNext();) { 99 MemRegion mr = itr.next(); 100 usedSize += mr.byteSize(); 101 } 102 return usedSize; 103 } 104 105 public long free() { 106 // small chunks 107 long size = 0; 108 Address cur = addr.addOffsetTo( indexedFreeListField.getOffset() ); 109 cur = cur.addOffsetTo(IndexSetStart*AdaptiveFreeList.sizeOf()); 110 for (int i=IndexSetStart; i<IndexSetSize; i += IndexSetStride) { 111 AdaptiveFreeList freeList = (AdaptiveFreeList) VMObjectFactory.newObject(AdaptiveFreeList.class, cur); 112 size += i*freeList.count(); 113 cur= cur.addOffsetTo(IndexSetStride*AdaptiveFreeList.sizeOf()); 114 } 115 116 // large block 117 AFLBinaryTreeDictionary aflbd = (AFLBinaryTreeDictionary) VMObjectFactory.newObject(AFLBinaryTreeDictionary.class, 118 dictionaryField.getValue(addr)); 119 size += aflbd.size(); 120 121 122 // linear block in TLAB 123 LinearAllocBlock lab = (LinearAllocBlock) VMObjectFactory.newObject(LinearAllocBlock.class, 124 addr.addOffsetTo(smallLinearAllocBlockFieldOffset)); 125 size += lab.word_size(); 126 127 return size*heapWordSize; 128 } 129 130 public void printOn(PrintStream tty) { 131 tty.print("free-list-space"); 132 tty.print("[ " + bottom() + " , " + end() + " ) "); 133 long cap = capacity(); 134 long used_size = used(); 135 long free_size = free(); 136 int used_perc = (int)((double)used_size/cap*100); 137 tty.print("space capacity = " + cap + " used(" + used_perc + "%)= " + used_size + " "); 138 tty.print("free= " + free_size ); 139 tty.print("\n"); 140 141 } 142 143 public Address skipBlockSizeUsingPrintezisBits(Address pos) { 144 CMSCollector collector = collector(); 145 long size = 0; 146 Address addr = null; 147 148 if (collector != null) { 149 size = collector.blockSizeUsingPrintezisBits(pos); 150 if (size >= 3) { 151 addr = pos.addOffsetTo(adjustObjectSizeInBytes(size)); 152 } 153 } 154 return addr; 155 } 156 157 @Override 158 public List<MemRegion> getLiveRegions() { 159 List<MemRegion> res = new ArrayList<>(); 160 VM vm = VM.getVM(); 161 Debugger dbg = vm.getDebugger(); 162 ObjectHeap heap = vm.getObjectHeap(); 163 Address cur = bottom(); 164 Address regionStart = cur; 165 Address limit = end(); 166 final long addressSize = vm.getAddressSize(); 167 168 for (; cur.lessThan(limit);) { 169 Address k = cur.getAddressAt(addressSize); 170 if (FreeChunk.indicatesFreeChunk(cur)) { 171 if (! cur.equals(regionStart)) { 172 res.add(new MemRegion(regionStart, cur)); 173 } 174 FreeChunk fc = (FreeChunk) VMObjectFactory.newObject(FreeChunk.class, cur); 175 long chunkSize = fc.size(); 176 if (Assert.ASSERTS_ENABLED) { 177 Assert.that(chunkSize > 0, "invalid FreeChunk size"); 178 } 179 // note that fc.size() gives chunk size in heap words 180 cur = cur.addOffsetTo(chunkSize * addressSize); 181 regionStart = cur; 182 } else if (k != null) { 183 Oop obj = heap.newOop(cur.addOffsetToAsOopHandle(0)); 184 long objectSize = obj.getObjectSize(); 185 cur = cur.addOffsetTo(adjustObjectSizeInBytes(objectSize)); 186 } else { 187 // FIXME: need to do a better job here. 188 // can I use bitMap here? 189 //Find the object size using Printezis bits and skip over 190 long size = collector().blockSizeUsingPrintezisBits(cur); 191 if (size == -1) { 192 break; 193 } 194 cur = cur.addOffsetTo(adjustObjectSizeInBytes(size)); 195 } 196 } 197 return res; 198 } 199 200 //-- Internals only below this point 201 202 // Unlike corresponding VM code, we operate on byte size rather than 203 // HeapWord size for convenience. 204 205 public static long adjustObjectSizeInBytes(long sizeInBytes) { 206 return Oop.alignObjectSize(Math.max(sizeInBytes, MinChunkSizeInBytes)); 207 } 208 209 }