Index: lucene/core/src/test/org/apache/lucene/util/TestRamUsageEstimator.java =================================================================== --- lucene/core/src/test/org/apache/lucene/util/TestRamUsageEstimator.java (revision 1300510) +++ lucene/core/src/test/org/apache/lucene/util/TestRamUsageEstimator.java (working copy) @@ -35,6 +35,23 @@ rue.estimateRamUsage(strings); } + public void testCompressedOops() { + if (VERBOSE) { + System.out.println("NOTE: This JVM is 64bit: " + Constants.JRE_IS_64BIT); + System.out.println("NOTE: This JVM uses CompressedOops: " + Constants.JRE_USES_COMPRESSED_OOPS); + } + if (Constants.JRE_IS_64BIT) { + if (Constants.JRE_USES_COMPRESSED_OOPS) { + assertEquals(4, RamUsageEstimator.NUM_BYTES_OBJECT_REF); + } else { + assertEquals(8, RamUsageEstimator.NUM_BYTES_OBJECT_REF); + } + } else { + assertFalse(Constants.JRE_USES_COMPRESSED_OOPS); + assertEquals(4, RamUsageEstimator.NUM_BYTES_OBJECT_REF); + } + } + private static final class Holder { long field1 = 5000L; String name = "name"; Index: lucene/core/src/java/org/apache/lucene/util/Constants.java =================================================================== --- lucene/core/src/java/org/apache/lucene/util/Constants.java (revision 1300510) +++ lucene/core/src/java/org/apache/lucene/util/Constants.java (working copy) @@ -17,6 +17,8 @@ * limitations under the License. */ +import java.lang.management.ManagementFactory; + import org.apache.lucene.LucenePackage; /** @@ -51,6 +53,7 @@ public static final boolean JRE_IS_64BIT; public static final boolean JRE_IS_MINIMUM_JAVA7; + public static final boolean JRE_USES_COMPRESSED_OOPS; static { // NOTE: this logic may not be correct; if you know of a // more reliable approach please raise it on java-dev! @@ -73,6 +76,28 @@ v7 = false; } JRE_IS_MINIMUM_JAVA7 = v7; + + boolean compressedOops = false; + if (JRE_IS_64BIT) { + try { + final Class beanClazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); + final Object hotSpotBean = ManagementFactory.newPlatformMXBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + "com.sun.management:type=HotSpotDiagnostic", + beanClazz + ); + final Object vmOption = hotSpotBean.getClass().getMethod("getVMOption", String.class) + .invoke(hotSpotBean, "UseCompressedOops"); + compressedOops = Boolean.valueOf( + vmOption.getClass().getMethod("getValue") + .invoke(vmOption).toString() + ).booleanValue(); + } catch (Exception e) { + // if anything fails before, we assume that oops are not compressed + compressedOops = false; + } + } + JRE_USES_COMPRESSED_OOPS = compressedOops; } // this method prevents inlining the final version constant in compiled classes, Index: lucene/core/src/java/org/apache/lucene/util/RamUsageEstimator.java =================================================================== --- lucene/core/src/java/org/apache/lucene/util/RamUsageEstimator.java (revision 1300510) +++ lucene/core/src/java/org/apache/lucene/util/RamUsageEstimator.java (working copy) @@ -45,9 +45,71 @@ public final static int NUM_BYTES_DOUBLE = 8; public final static int NUM_BYTES_CHAR = 2; public final static int NUM_BYTES_OBJECT_HEADER = 8; - public final static int NUM_BYTES_OBJECT_REF = Constants.JRE_IS_64BIT ? 8 : 4; - public final static int NUM_BYTES_ARRAY_HEADER = NUM_BYTES_OBJECT_HEADER + NUM_BYTES_INT + NUM_BYTES_OBJECT_REF; + public final static int NUM_BYTES_OBJECT_REF = (Constants.JRE_IS_64BIT && !Constants.JRE_USES_COMPRESSED_OOPS) ? 8 : 4; + public final static int NUM_BYTES_ARRAY_HEADER = NUM_BYTES_OBJECT_HEADER + NUM_BYTES_INT /* array length */; + + /** Aligns an object size to be the next multiple of 8. */ + public static int alignObjectSize(int size) { + return (size + 7) & 0x7FFFFFF8; + } + + /** Returns the size in bytes of the byte[] object. */ + public static int sizeOf(byte[] arr) { + return alignObjectSize(NUM_BYTES_ARRAY_HEADER + arr.length); + } + + /** Returns the size in bytes of the char[] object. */ + public static int sizeOf(char[] arr) { + return alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_CHAR * arr.length); + } + /** Returns the size in bytes of the short[] object. */ + public static int sizeOf(short[] arr) { + return alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_SHORT * arr.length); + } + + /** Returns the size in bytes of the int[] object. */ + public static int sizeOf(int[] arr) { + return alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_INT * arr.length); + } + + /** Returns the size in bytes of the float[] object. */ + public static int sizeOf(float[] arr) { + return alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_FLOAT * arr.length); + } + + /** Returns the size in bytes of the long[] object. */ + public static int sizeOf(long[] arr) { + return alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_LONG * arr.length); + } + + /** Returns the size in bytes of the double[] object. */ + public static int sizeOf(double[] arr) { + return alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_DOUBLE * arr.length); + } + + /** Returns the size in bytes of the String[] object. */ + public static int sizeOf(String[] arr) { + int size = alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_OBJECT_REF * arr.length); + for (String s : arr) { + size += sizeOf(s); + } + return size; + } + + /** Returns the approximate size of a String object. */ + public static int sizeOf(String str) { + // String's char[] size + int arraySize = alignObjectSize(NUM_BYTES_ARRAY_HEADER + NUM_BYTES_CHAR * str.length()); + + // String's row object size + int objectSize = alignObjectSize(NUM_BYTES_OBJECT_REF /* array reference */ + + 3 * NUM_BYTES_INT /* String holds 3 integers */ + + NUM_BYTES_OBJECT_HEADER /* String object header */); + + return objectSize + arraySize; + } + private MemoryModel memoryModel; private final Map seen;