Index: lucene/core/src/java/org/apache/lucene/util/Constants.java =================================================================== --- lucene/core/src/java/org/apache/lucene/util/Constants.java (revision 1300016) +++ lucene/core/src/java/org/apache/lucene/util/Constants.java (working copy) @@ -17,6 +17,11 @@ * limitations under the License. */ +import java.lang.management.ManagementFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.regex.Pattern; + import org.apache.lucene.LucenePackage; /** @@ -51,6 +56,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 +79,39 @@ 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 Method getVMOptionMethod = hotSpotBean.getClass().getMethod("getVMOption", String.class); + Object vmOption; + try { + // Sun/Oracle JVM + vmOption = getVMOptionMethod.invoke(hotSpotBean, "UseCompressedOops"); + } catch (InvocationTargetException ite) { + // jRockit + vmOption = getVMOptionMethod.invoke(hotSpotBean, "CompressedRefs"); + } + 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, last chance is IBM J9 via sysprops + compressedOops = + Pattern.compile("\\bIBM\\b", Pattern.CASE_INSENSITIVE) + .matcher(System.getProperty("java.vm.vendor", "")).find() + && Pattern.compile("\\bCompressed\\sReferences\\b", Pattern.CASE_INSENSITIVE) + .matcher(System.getProperty("java.vm.info", "")).find(); + } + } + 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 1300016) +++ 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; Index: lucene/core/src/test/org/apache/lucene/util/TestRamUsageEstimator.java =================================================================== --- lucene/core/src/test/org/apache/lucene/util/TestRamUsageEstimator.java (revision 1300016) +++ 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";