1 /* 2 * Copyright (c) 2014, 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 import java.lang.management.MemoryPoolMXBean; 25 import java.util.Optional; 26 27 import sun.hotspot.WhiteBox; 28 29 /** 30 * Helper class aimed to provide information about alignment of objects in 31 * particular heap space, expected memory usage after objects' allocation so on. 32 */ 33 public class AlignmentHelper { 34 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 35 36 private static final long OBJECT_ALIGNMENT_IN_BYTES_FOR_32_VM = 8L; 37 38 /** 39 * Max relative allowed actual memory usage deviation from expected memory 40 * usage. 41 */ 42 private static final float MAX_RELATIVE_DEVIATION = 0.05f; // 5% 43 44 public static final long OBJECT_ALIGNMENT_IN_BYTES = Optional.ofNullable( 45 AlignmentHelper.WHITE_BOX.getIntxVMFlag("ObjectAlignmentInBytes")) 46 .orElse(AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES_FOR_32_VM); 47 48 public static final long SURVIVOR_ALIGNMENT_IN_BYTES = Optional.ofNullable( 49 AlignmentHelper.WHITE_BOX.getIntxVMFlag("SurvivorAlignmentInBytes")) 50 .orElseThrow(() ->new AssertionError( 51 "Unable to get SurvivorAlignmentInBytes value")); 52 /** 53 * Min amount of memory that will be occupied by an object. 54 */ 55 public static final long MIN_OBJECT_SIZE 56 = AlignmentHelper.WHITE_BOX.getObjectSize(new Object()); 57 /** 58 * Min amount of memory that will be occupied by an empty byte array. 59 */ 60 public static final long MIN_ARRAY_SIZE 61 = AlignmentHelper.WHITE_BOX.getObjectSize(new byte[0]); 62 63 /** 64 * Precision at which actual memory usage in a heap space represented by 65 * this sizing helper could be measured. 66 */ 67 private final long memoryUsageMeasurementPrecision; 68 /** 69 * Min amount of memory that will be occupied by an object allocated in a 70 * heap space represented by this sizing helper. 71 */ 72 private final long minObjectSizeInThisSpace; 73 /** 74 * Object's alignment in a heap space represented by this sizing helper. 75 */ 76 private final long objectAlignmentInThisRegion; 77 /** 78 * MemoryPoolMXBean associated with a heap space represented by this sizing 79 * helper. 80 */ 81 private final MemoryPoolMXBean poolMXBean; 82 83 private static long alignUp(long value, long alignment) { 84 return ((value - 1) / alignment + 1) * alignment; 85 } 86 87 protected AlignmentHelper(long memoryUsageMeasurementPrecision, 88 long objectAlignmentInThisRegion, long minObjectSizeInThisSpace, 89 MemoryPoolMXBean poolMXBean) { 90 this.memoryUsageMeasurementPrecision = memoryUsageMeasurementPrecision; 91 this.minObjectSizeInThisSpace = minObjectSizeInThisSpace; 92 this.objectAlignmentInThisRegion = objectAlignmentInThisRegion; 93 this.poolMXBean = poolMXBean; 94 } 95 96 /** 97 * Returns how many objects have to be allocated to fill 98 * {@code memoryToFill} bytes in this heap space using objects of size 99 * {@code objectSize}. 100 */ 101 public int getObjectsCount(long memoryToFill, long objectSize) { 102 return (int) (memoryToFill / getObjectSizeInThisSpace(objectSize)); 103 } 104 105 /** 106 * Returns amount of memory that {@code objectsCount} of objects with size 107 * {@code objectSize} will occupy this this space after allocation. 108 */ 109 public long getExpectedMemoryUsage(long objectSize, int objectsCount) { 110 long correctedObjectSize = getObjectSizeInThisSpace(objectSize); 111 return AlignmentHelper.alignUp(correctedObjectSize * objectsCount, 112 memoryUsageMeasurementPrecision); 113 } 114 115 /** 116 * Returns current memory usage in this heap space. 117 */ 118 public long getActualMemoryUsage() { 119 return poolMXBean.getUsage().getUsed(); 120 } 121 122 /** 123 * Returns maximum memory usage deviation from {@code expectedMemoryUsage} 124 * given the max allowed relative deviation equal to 125 * {@code relativeDeviation}. 126 * 127 * Note that value returned by this method is aligned according to 128 * memory measurement precision for this heap space. 129 */ 130 public long getAllowedMemoryUsageDeviation(long expectedMemoryUsage) { 131 long unalignedDeviation = (long) (expectedMemoryUsage * 132 AlignmentHelper.MAX_RELATIVE_DEVIATION); 133 return AlignmentHelper.alignUp(unalignedDeviation, 134 memoryUsageMeasurementPrecision); 135 } 136 137 /** 138 * Returns amount of memory that will be occupied by an object with size 139 * {@code objectSize} in this heap space. 140 */ 141 public long getObjectSizeInThisSpace(long objectSize) { 142 objectSize = Math.max(objectSize, minObjectSizeInThisSpace); 143 144 long alignedObjectSize = AlignmentHelper.alignUp(objectSize, 145 objectAlignmentInThisRegion); 146 long sizeDiff = alignedObjectSize - objectSize; 147 148 // If there is not enough space to fit padding object, then object will 149 // be aligned to {@code 2 * objectAlignmentInThisRegion}. 150 if (sizeDiff >= AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES 151 && sizeDiff < AlignmentHelper.MIN_OBJECT_SIZE) { 152 alignedObjectSize += AlignmentHelper.MIN_OBJECT_SIZE; 153 alignedObjectSize = AlignmentHelper.alignUp(alignedObjectSize, 154 objectAlignmentInThisRegion); 155 } 156 157 return alignedObjectSize; 158 } 159 @Override 160 public String toString() { 161 StringBuilder builder = new StringBuilder(); 162 163 builder.append(String.format("AlignmentHelper for memory pool '%s':%n", 164 poolMXBean.getName())); 165 builder.append(String.format("Memory usage measurement precision: %d%n", 166 memoryUsageMeasurementPrecision)); 167 builder.append(String.format("Min object size in this space: %d%n", 168 minObjectSizeInThisSpace)); 169 builder.append(String.format("Object alignment in this space: %d%n", 170 objectAlignmentInThisRegion)); 171 172 return builder.toString(); 173 } 174 }