Created
December 30, 2012 07:38
-
-
Save coderplay/4411425 to your computer and use it in GitHub Desktop.
Direct Memory Tricks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.management.GarbageCollectorMXBean; | |
import java.lang.management.ManagementFactory; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Modifier; | |
import javax.management.MBeanServer; | |
import javax.management.ObjectName; | |
import javax.management.openmbean.CompositeData; | |
import sun.misc.Unsafe; | |
/** | |
* Detects and represents JVM-specific properties that relate to the memory data | |
* model for java objects that are useful for size of calculations. | |
* | |
* @author jhouse | |
* @author Chris Dennis | |
*/ | |
enum JvmInformation { | |
/** | |
* Represents HotSpot 32-bit | |
*/ | |
HOTSPOT_32_BIT { | |
/* default values are for this vm */ | |
@Override | |
public String getJvmDescription() { | |
return "32-Bit HotSpot JVM"; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 32-Bit HotSpot JVM with Concurrent Mark-and-Sweep GC | |
*/ | |
HOTSPOT_32_BIT_WITH_CONCURRENT_MARK_AND_SWEEP { | |
@Override | |
public int getMinimumObjectSize() { | |
return 16; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "32-Bit HotSpot JVM with Concurrent Mark-and-Sweep GC"; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 64-Bit HotSpot JVM | |
*/ | |
HOTSPOT_64_BIT { | |
@Override | |
public int getPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 8; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit HotSpot JVM"; | |
} | |
}, | |
/** | |
* Represents 64-Bit HotSpot JVM with Concurrent Mark-and-Sweep GC | |
*/ | |
HOTSPOT_64_BIT_WITH_CONCURRENT_MARK_AND_SWEEP { | |
@Override | |
public int getPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getMinimumObjectSize() { | |
return 24; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit HotSpot JVM with Concurrent Mark-and-Sweep GC"; | |
} | |
}, | |
/** | |
* Represents 64-Bit HotSpot JVM with Compressed OOPs | |
*/ | |
HOTSPOT_64_BIT_WITH_COMPRESSED_OOPS { | |
@Override | |
public int getPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit HotSpot JVM with Compressed OOPs"; | |
} | |
}, | |
/** | |
* Represents 64-Bit HotSpot JVM with Compressed OOPs and Concurrent | |
* Mark-and-Sweep GC | |
*/ | |
HOTSPOT_64_BIT_WITH_COMPRESSED_OOPS_AND_CONCURRENT_MARK_AND_SWEEP { | |
@Override | |
public int getPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getMinimumObjectSize() { | |
return 24; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit HotSpot JVM with Compressed OOPs and Concurrent Mark-and-Sweep GC"; | |
} | |
}, | |
/** | |
* Represents 32-Bit JRockit JVM" | |
*/ | |
JROCKIT_32_BIT { | |
@Override | |
public int getAgentSizeOfAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getFieldOffsetAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 16; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "32-Bit JRockit JVM"; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 64-Bit JRockit JVM (with no reference compression) | |
*/ | |
JROCKIT_64_BIT { | |
@Override | |
public int getAgentSizeOfAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getFieldOffsetAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 16; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit JRockit JVM (with no reference compression)"; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 64-Bit JRockit JVM with 4GB Compressed References | |
*/ | |
JROCKIT_64_BIT_WITH_4GB_COMPRESSED_REFS { | |
@Override | |
public int getAgentSizeOfAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getFieldOffsetAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 16; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit JRockit JVM with 4GB Compressed References"; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 64-Bit JRockit JVM with 32GB Compressed References | |
*/ | |
JROCKIT_64_BIT_WITH_32GB_COMPRESSED_REFS { | |
@Override | |
public int getAgentSizeOfAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getFieldOffsetAdjustment() { | |
return 8; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 16; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit JRockit JVM with 32GB Compressed References"; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 64-Bit JRockit JVM with 64GB Compressed References | |
*/ | |
JROCKIT_64_BIT_WITH_64GB_COMPRESSED_REFS { | |
@Override | |
public int getObjectAlignment() { | |
return 16; | |
} | |
@Override | |
public int getAgentSizeOfAdjustment() { | |
return 16; | |
} | |
@Override | |
public int getFieldOffsetAdjustment() { | |
return 16; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 24; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "64-Bit JRockit JVM with 64GB Compressed References"; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 64-Bit IBM JVM (with reference compression) | |
*/ | |
IBM_64_BIT_WITH_COMPRESSED_REFS { | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 16; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "IBM 64-Bit JVM with Compressed References"; | |
} | |
}, | |
/** | |
* Represents 64-Bit IBM JVM (with no reference compression) | |
*/ | |
IBM_64_BIT { | |
@Override | |
public int getPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 24; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "IBM 64-Bit JVM (with no reference compression)"; | |
} | |
}, | |
/** | |
* Represents IBM 32-bit | |
*/ | |
IBM_32_BIT { | |
/* default values are for this vm */ | |
@Override | |
public String getJvmDescription() { | |
return "IBM 32-Bit JVM"; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getObjectHeaderSize() { | |
return 16; | |
} | |
@Override | |
public boolean supportsReflectionSizeOf() { | |
return false; | |
} | |
}, | |
/** | |
* Represents Generic 32-bit | |
*/ | |
UNKNOWN_32_BIT { | |
/* default values are for this vm */ | |
@Override | |
public String getJvmDescription() { | |
return "Unrecognized 32-Bit JVM"; | |
} | |
@Override | |
public int getPointerSize() { | |
return 4; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 4; | |
} | |
}, | |
/** | |
* Represents 64-Bit Generic JVM | |
*/ | |
UNKNOWN_64_BIT { | |
@Override | |
public int getPointerSize() { | |
return 8; | |
} | |
@Override | |
public int getJavaPointerSize() { | |
return 8; | |
} | |
@Override | |
public String getJvmDescription() { | |
return "Unrecognized 64-Bit JVM"; | |
} | |
}; | |
/** | |
* The JvmInformation instance representing the current JVM | |
*/ | |
public static final JvmInformation CURRENT_JVM_INFORMATION; | |
private static final long THREE_GB = 3L * 1024L * 1024L * 1024L; | |
private static final long TWENTY_FIVE_GB = 25L * 1024L * 1024L * 1024L; | |
private static final long FIFTY_SEVEN_GB = 57L * 1024L * 1024L * 1024L; | |
static { | |
CURRENT_JVM_INFORMATION = getJvmInformation(); | |
System.out.println("Detected JVM data model settings of: " | |
+ CURRENT_JVM_INFORMATION.getJvmDescription()); | |
} | |
/** | |
* Size of a pointer in bytes on this runtime | |
*/ | |
public abstract int getPointerSize(); | |
/** | |
* Size of a java pointer in bytes on this runtime (that differs when | |
* compressedOops are being used) | |
*/ | |
public abstract int getJavaPointerSize(); | |
/** | |
* Minimal size an object will occupy on the heap in bytes. | |
*/ | |
public int getMinimumObjectSize() { | |
return getObjectAlignment(); | |
} | |
/** | |
* Object alignment / padding in bytes | |
*/ | |
public int getObjectAlignment() { | |
return 8; | |
} | |
/** | |
* The size of an object header in bytes. | |
*/ | |
public int getObjectHeaderSize() { | |
return getPointerSize() + getJavaPointerSize(); | |
} | |
/** | |
* The size of the jvm-specific field offset adjustment in bytes. | |
*/ | |
public int getFieldOffsetAdjustment() { | |
return 0; | |
} | |
/** | |
* The size of the jvm-specific agent result adjustment in bytes. | |
*/ | |
public int getAgentSizeOfAdjustment() { | |
return 0; | |
} | |
/** | |
* Whether the jvm can support AgentSizeOf implementation. | |
*/ | |
public boolean supportsAgentSizeOf() { | |
return true; | |
} | |
/** | |
* Whether the jvm can support UnsafeSizeOf implementation. | |
*/ | |
public boolean supportsUnsafeSizeOf() { | |
return true; | |
} | |
/** | |
* Whether the jvm can support ReflectionSizeOf implementation. | |
*/ | |
public boolean supportsReflectionSizeOf() { | |
return true; | |
} | |
/** | |
* A human-readable description of the JVM and its relevant enabled options.Os | |
*/ | |
public abstract String getJvmDescription(); | |
/** | |
* Determine the JvmInformation for the current JVM. | |
*/ | |
private static JvmInformation getJvmInformation() { | |
JvmInformation jif = null; | |
jif = detectHotSpot(); | |
if (jif == null) { | |
jif = detectJRockit(); | |
} | |
if (jif == null) { | |
jif = detectIBM(); | |
} | |
if (jif == null && is64Bit()) { | |
// unknown 64-bit JVMs | |
jif = UNKNOWN_64_BIT; | |
} else if (jif == null) { | |
// unknown 32-bit JVMs | |
jif = UNKNOWN_32_BIT; | |
} | |
return jif; | |
} | |
private static JvmInformation detectHotSpot() { | |
JvmInformation jif = null; | |
if (isHotspot()) { | |
if (is64Bit()) { | |
if (isHotspotCompressedOops() && isHotspotConcurrentMarkSweepGC()) { | |
jif = | |
HOTSPOT_64_BIT_WITH_COMPRESSED_OOPS_AND_CONCURRENT_MARK_AND_SWEEP; | |
} else if (isHotspotCompressedOops()) { | |
jif = HOTSPOT_64_BIT_WITH_COMPRESSED_OOPS; | |
} else if (isHotspotConcurrentMarkSweepGC()) { | |
jif = HOTSPOT_64_BIT_WITH_CONCURRENT_MARK_AND_SWEEP; | |
} else { | |
jif = HOTSPOT_64_BIT; | |
} | |
} else { | |
jif = HOTSPOT_32_BIT; | |
} | |
} | |
return jif; | |
} | |
private static JvmInformation detectJRockit() { | |
JvmInformation jif = null; | |
if (isJRockit()) { | |
if (is64Bit()) { | |
if (isJRockit4GBCompression()) { | |
jif = JROCKIT_64_BIT_WITH_4GB_COMPRESSED_REFS; | |
} else if (isJRockit32GBCompression()) { | |
jif = JROCKIT_64_BIT_WITH_32GB_COMPRESSED_REFS; | |
} else if (isJRockit64GBCompression()) { | |
jif = JROCKIT_64_BIT_WITH_64GB_COMPRESSED_REFS; | |
} else { | |
jif = JROCKIT_64_BIT; | |
} | |
} else { | |
jif = JROCKIT_32_BIT; | |
} | |
} | |
return jif; | |
} | |
private static JvmInformation detectIBM() { | |
JvmInformation jif = null; | |
if (isIBM()) { | |
if (is64Bit()) { | |
if (isIBMCompressedRefs()) { | |
jif = IBM_64_BIT_WITH_COMPRESSED_REFS; | |
} else { | |
jif = IBM_64_BIT; | |
} | |
} else { | |
jif = IBM_32_BIT; | |
} | |
} | |
return jif; | |
} | |
private static boolean isJRockit32GBCompression() { | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:enable=false")) { | |
return false; | |
} | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:size=64GB") | |
|| getJRockitVmArgs().contains("-XXcompressedRefs:size=4GB")) { | |
return false; | |
} | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:size=32GB")) { | |
return true; | |
} | |
if (Runtime.getRuntime().maxMemory() > THREE_GB | |
&& Runtime.getRuntime().maxMemory() <= TWENTY_FIVE_GB | |
&& getJRockitVmArgs().contains("-XXcompressedRefs:enable=true")) { | |
return true; | |
} | |
return false; | |
} | |
private static boolean isJRockit64GBCompression() { | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:enable=false")) { | |
return false; | |
} | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:size=4GB") | |
|| getJRockitVmArgs().contains("-XXcompressedRefs:size=32GB")) { | |
return false; | |
} | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:size=64GB")) { | |
return true; | |
} | |
if (Runtime.getRuntime().maxMemory() > TWENTY_FIVE_GB | |
&& Runtime.getRuntime().maxMemory() <= FIFTY_SEVEN_GB | |
&& getJRockitVmArgs().contains("-XXcompressedRefs:enable=true")) { | |
return true; | |
} | |
return false; | |
} | |
private static boolean isJRockit4GBCompression() { | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:enable=false")) { | |
return false; | |
} | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:size=64GB") | |
|| getJRockitVmArgs().contains("-XXcompressedRefs:size=32GB")) { | |
return false; | |
} | |
if (getJRockitVmArgs().contains("-XXcompressedRefs:size=4GB")) { | |
return true; | |
} | |
if (Runtime.getRuntime().maxMemory() <= THREE_GB) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Returns true if VM is JRockit | |
* | |
* @return true, if JRockit | |
*/ | |
public static boolean isJRockit() { | |
return System.getProperty("jrockit.version") != null | |
|| System.getProperty("java.vm.name", "").toLowerCase() | |
.indexOf("jrockit") >= 0; | |
} | |
/** | |
* Return true if the VM's vendor is Apple | |
* | |
* @return true, if OS X | |
*/ | |
public static boolean isOSX() { | |
final String vendor = System.getProperty("java.vm.vendor"); | |
return vendor != null && vendor.startsWith("Apple"); | |
} | |
/** | |
* Returns true if VM vendor is Hotspot | |
* | |
* @return true, if Hotspot | |
*/ | |
public static boolean isHotspot() { | |
return System.getProperty("java.vm.name", "").toLowerCase() | |
.contains("hotspot"); | |
} | |
/** | |
* Returns true if VM vendor is IBM | |
* | |
* @return true, if IBM | |
*/ | |
public static boolean isIBM() { | |
return System.getProperty("java.vm.name", "").contains("IBM") | |
&& System.getProperty("java.vm.vendor").contains("IBM"); | |
} | |
private static boolean isIBMCompressedRefs() { | |
return System.getProperty("com.ibm.oti.vm.bootstrap.library.path", "") | |
.contains("compressedrefs"); | |
} | |
private static boolean isHotspotCompressedOops() { | |
String value = getHotSpotVmOptionValue("UseCompressedOops"); | |
if (value == null) { | |
return false; | |
} else { | |
return Boolean.valueOf(value); | |
} | |
} | |
private static String getHotSpotVmOptionValue(String name) { | |
try { | |
MBeanServer server = ManagementFactory.getPlatformMBeanServer(); | |
ObjectName beanName = | |
ObjectName.getInstance("com.sun.management:type=HotSpotDiagnostic"); | |
Object vmOption = | |
server.invoke(beanName, "getVMOption", new Object[] { name }, | |
new String[] { "java.lang.String" }); | |
return (String) ((CompositeData) vmOption).get("value"); | |
} catch (Throwable t) { | |
return null; | |
} | |
} | |
private static String getPlatformMBeanAttribute(String beanName, | |
String attrName) { | |
try { | |
MBeanServer server = ManagementFactory.getPlatformMBeanServer(); | |
ObjectName name = ObjectName.getInstance(beanName); | |
Object attr = server.getAttribute(name, attrName).toString(); | |
if (attr != null) { | |
return attr.toString(); | |
} | |
return null; | |
} catch (Throwable t) { | |
return null; | |
} | |
} | |
private static String getJRockitVmArgs() { | |
return getPlatformMBeanAttribute( | |
"oracle.jrockit.management:type=PerfCounters", "java.rt.vmArgs"); | |
} | |
private static boolean isHotspotConcurrentMarkSweepGC() { | |
for (GarbageCollectorMXBean bean : ManagementFactory | |
.getGarbageCollectorMXBeans()) { | |
if ("ConcurrentMarkSweep".equals(bean.getName())) { | |
return true; | |
} | |
} | |
return false; | |
} | |
private static boolean is64Bit() { | |
String systemProp; | |
systemProp = System.getProperty("com.ibm.vm.bitmode"); | |
if (systemProp != null) { | |
return systemProp.equals("64"); | |
} | |
systemProp = System.getProperty("sun.arch.data.model"); | |
if (systemProp != null) { | |
return systemProp.equals("64"); | |
} | |
systemProp = System.getProperty("java.vm.version"); | |
if (systemProp != null) { | |
return systemProp.contains("_64"); | |
} | |
return false; | |
} | |
} | |
class Person { | |
String name; | |
int age; | |
} | |
class Pointer { | |
Object pointer; | |
Object value; | |
} | |
public class DirectMemoryTricky { | |
private static final Unsafe unsafe; | |
static { | |
try { | |
Field field = Unsafe.class.getDeclaredField("theUnsafe"); | |
field.setAccessible(true); | |
unsafe = (Unsafe) field.get(null); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
public static long sizeOf(Object obj) { | |
if (obj.getClass().isArray()) { | |
Class<?> klazz = obj.getClass(); | |
int base = unsafe.arrayBaseOffset(klazz); | |
int scale = unsafe.arrayIndexScale(klazz); | |
long size = base + (scale * Array.getLength(obj)); | |
size += JvmInformation.CURRENT_JVM_INFORMATION.getFieldOffsetAdjustment(); | |
if ((size % JvmInformation.CURRENT_JVM_INFORMATION.getObjectAlignment()) != 0) { | |
size += | |
JvmInformation.CURRENT_JVM_INFORMATION.getObjectAlignment() | |
- (size % JvmInformation.CURRENT_JVM_INFORMATION | |
.getObjectAlignment()); | |
} | |
return Math.max( | |
JvmInformation.CURRENT_JVM_INFORMATION.getMinimumObjectSize(), size); | |
} else { | |
for (Class<?> klazz = obj.getClass(); klazz != null; klazz = | |
klazz.getSuperclass()) { | |
long lastFieldOffset = -1; | |
for (Field f : klazz.getDeclaredFields()) { | |
if (!Modifier.isStatic(f.getModifiers())) { | |
lastFieldOffset = | |
Math.max(lastFieldOffset, unsafe.objectFieldOffset(f)); | |
} | |
} | |
if (lastFieldOffset > 0) { | |
lastFieldOffset += | |
JvmInformation.CURRENT_JVM_INFORMATION.getFieldOffsetAdjustment(); | |
lastFieldOffset += 1; | |
if ((lastFieldOffset % JvmInformation.CURRENT_JVM_INFORMATION | |
.getObjectAlignment()) != 0) { | |
lastFieldOffset += | |
JvmInformation.CURRENT_JVM_INFORMATION.getObjectAlignment() | |
- (lastFieldOffset % JvmInformation.CURRENT_JVM_INFORMATION | |
.getObjectAlignment()); | |
} | |
return Math.max( | |
JvmInformation.CURRENT_JVM_INFORMATION.getMinimumObjectSize(), | |
lastFieldOffset); | |
} | |
} | |
long size = JvmInformation.CURRENT_JVM_INFORMATION.getObjectHeaderSize(); | |
if ((size % JvmInformation.CURRENT_JVM_INFORMATION.getObjectAlignment()) != 0) { | |
size += | |
JvmInformation.CURRENT_JVM_INFORMATION.getObjectAlignment() | |
- (size % JvmInformation.CURRENT_JVM_INFORMATION | |
.getObjectAlignment()); | |
} | |
return Math.max( | |
JvmInformation.CURRENT_JVM_INFORMATION.getMinimumObjectSize(), size); | |
} | |
} | |
public static void main(String[] args) throws Exception { | |
Person person = new Person(); | |
person.age = 30; | |
long size = sizeOf(person); | |
System.out.println(size); | |
long offheapPointer = unsafe.allocateMemory(size); | |
System.out.println("offheapPointer & 0xffffffff00000000L = " + (offheapPointer & 0xffffffff00000000L)); | |
unsafe.copyMemory(person, // source object | |
0, // source offset is zero - copy an entire object | |
null, // destination is specified by absolute address, so destination object is null | |
offheapPointer, // destination address | |
size); // test object was copied to off-heap | |
Pointer pointer = new Pointer(); // Pointer is just a handler that stores | |
// address | |
// of some object | |
long pointerOffset = | |
unsafe.objectFieldOffset(Pointer.class.getDeclaredField("pointer")); | |
long valueOffset = | |
unsafe.objectFieldOffset(Pointer.class.getDeclaredField("value")); | |
System.out.println("pointerOffset: " + pointerOffset + ", valueOffset:" + valueOffset); | |
// set pointer to off-heap | |
unsafe.putLong(pointer, pointerOffset, offheapPointer); | |
// copy of the test object | |
person.age = 23; // rewrite x value in the original object | |
System.out.println(((Person) pointer.pointer).age); // prints 30 | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$java -XX:+UseCompressedOops DirectMemoryTricky | |
Detected JVM data model settings of: 64-Bit HotSpot JVM with Compressed OOPs | |
24 | |
offheapPointer & 0xffffffff00000000L = 139736760975360 | |
pointerOffset: 12, valueOffset:16 | |
Exception in thread "main" java.lang.NullPointerException | |
at DirectMemoryTricky.main(DirectMemoryTricky.java:977) | |
$ java -XX:+UseCompressedOops DirectMemoryTricky | |
Detected JVM data model settings of: 64-Bit HotSpot JVM with Compressed OOPs | |
24 | |
offheapPointer & 0xffffffff00000000L = 140647294042112 | |
pointerOffset: 12, valueOffset:16 | |
# | |
# A fatal error has been detected by the Java Runtime Environment: | |
# | |
# SIGSEGV (0xb) at pc=0x00007feb4101cb53, pid=4374, tid=140648546432768 | |
# | |
# JRE version: 6.0_37-b06 | |
# Java VM: Java HotSpot(TM) 64-Bit Server VM (20.12-b01 mixed mode linux-amd64 compressed oops) | |
# Problematic frame: | |
# j DirectMemoryTricky.main([Ljava/lang/String;)V+177 | |
# | |
# An error report file with more information is saved as: | |
# /home/min/code/java/benchmark/hs_err_pid4374.log | |
# | |
# If you would like to submit a bug report, please visit: | |
# http://java.sun.com/webapps/bugreport/crash.jsp | |
# | |
Aborted (core dumped) | |
$ java -XX:-UseCompressedOops DirectMemoryTricky | |
Detected JVM data model settings of: 64-Bit HotSpot JVM | |
32 | |
offheapPointer & 0xffffffff00000000L = 140067473457152 | |
pointerOffset: 16, valueOffset:24 | |
30 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment