转:http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/
Java was initially designed as a safe, managed environment. Nevertheless, Java HotSpot VM contains a “backdoor” that provides a number of low-level operations to manipulate memory and threads directly. This backdoor – sun.misc.Unsafe – is widely used by JDK itself in the packages like java.nio or java.util.concurrent. It is hard to imagine a Java developer who uses this backdoor in any regular development because this API is extremely dangerous, non portable, and volatile. Nevertheless, Unsafe provides an easy way to look into HotSpot JVM internals and do some tricks. Sometimes it is simply funny, sometimes it can be used to study VM internals without C++ code debugging, sometimes it can be leveraged for profiling and development tools.
Obtaining Unsafe
The sun.misc.Unsafe class is so unsafe that JDK developers added special checks to restrict access to it. Its constructor is private and caller of the factory method getUnsafe() should be loaded by Bootloader (i.e. caller should also be a part of JDK):
01 |
public final class Unsafe {
|
04 |
private static final Unsafe theUnsafe = new Unsafe();
|
06 |
public static Unsafe getUnsafe() {
|
07 |
Class cc = sun.reflect.Reflection.getCallerClass( 2 );
|
08 |
if (cc.getClassLoader() != null )
|
09 |
throw new SecurityException( "Unsafe" );
|
Fortunately there is theUnsafe field that can be used to retrieve Unsafe instance. We can easily write a helper method to do this via reflection:
1 |
public static Unsafe getUnsafe() {
|
3 |
Field f = Unsafe. class .getDeclaredField( "theUnsafe" );
|
5 |
return (Unsafe)f.get( null );
|
6 |
} catch (Exception e) { }
|
In the next sections we will study several tricks that become possible due to the following methods of Unsafe:
-
long getAddress(long address) and void putAddress(long address, long x) that allows to read and write dwords directly from memory.
-
int getInt(Object o, long offset) , void putInt(Object o, long offset, int x), and other similar methods that allows to read and write data directly from C structure that represents Java object.
-
long allocateMemory(long bytes) which can be considered as a wrapper for C’s malloc().
sizeof() Function
The first trick we will do is C-like sizeof() function, i.e. function that returns shallow object size in bytes. Inspecting JVM sources of JDK6 and JDK7, in particular src/share/vm/oops/oop.hpp and src/share/vm/oops/klass.hpp, and reading comments in the code, we can notice that size of class instance is stored in _layout_helper which is the fourth field in C structure that represents Java class. Similarly, /src/share/vm/oops/oop.hpp shows that each instance (i.e. object) stores pointer to a class structure in its second field. For 32-bit JVM this means that we can first take class structure address as 4-8 bytes in the object structure and next shift by 3×4=12 bytes inside class structure to capture_layout_helper field which is instance size in bytes. These structures are shown in the picture below:
As so, we can implement sizeof() as follows:
1 |
public static long sizeOf(Object object) {
|
2 |
Unsafe unsafe = getUnsafe();
|
3 |
return unsafe.getAddress( normalize( unsafe.getInt(object, 4L) ) + 12L );
|
6 |
public static long normalize( int value) {
|
7 |
if (value >= 0 ) return value;
|
8 |
return (~0L >>> 32 ) & value;
|
We need to use normalize() function because addresses between 2^31 and 2^32 will be automatically converted to negative integers, i.e. stored in complement form. Let’s test it on 32-bit JVM (JDK 6 or 7):
4 |
class MyStructure { int x; }
|
5 |
class MyStructure { int x; int y; }
|
This function will not work for array objects, because _layout_helper field has another meaning in that case. Although it is still possible to generalize sizeOf() to support arrays.
Direct Memory Management
Unsafe allows to allocate and deallocate memory explicitly via allocateMemory and freeMemory methods. Allocated memory is not under GC control and not limited by maximum JVM heap size. In general, such functionality is safely available via NIO’s off-heap bufferes. But the interesting thing is that it is possible to map standard Java reference to off-heap memory:
01 |
MyStructure structure = new MyStructure();
|
04 |
long size = sizeOf(structure);
|
05 |
long offheapPointer = getUnsafe().allocateMemory(size);
|
06 |
getUnsafe().copyMemory( |
14 |
Pointer p = new Pointer();
|
15 |
long pointerOffset = getUnsafe().objectFieldOffset(Pointer. class .getDeclaredField( "pointer" ));
|
16 |
getUnsafe().putLong(p, pointerOffset, offheapPointer);
|
19 |
System.out.println( ((MyStructure)p.pointer).x );
|
So, it is virtually possible to manually allocate and deallocate real objects, not only byte buffers. Of course, it’s a big question what may happen with GC after such cheats.
Inheritance from Final Class and void*
Imagine the situation when one has a method that takes a string as an argument, but it is necessary to pass some extra payload. There are at least two standard ways to do it in Java: put payload to thread local or use static field. With Unsafe another two possibilities appears: pass payload address as a string and inherit payload class from String class. The first approach is pretty close to what we see in the previous section – one just need obtain payload address using Pointer and create a new Pointer to payload inside the called method. In other words, any argument that can carrier an address can be used as analog of void* in C. In order to explore the second approach we start with the following code which is compilable, but obviously produces ClassCastException in run time:
01 |
Carrier carrier = new Carrier();
|
04 |
String message = (String)(Object)carrier;
|
09 |
void handler(String message) {
|
10 |
System.out.println( ((Carrier)(Object)message).secret );
|
To make it work, one need to modify Carrier class to simulate inheritance from String. A list of superclasses is stored in Carrier class structure starting from position 28, as it shown in the figure. Pointer to object goes first and pointer to Carrier itself goes after it (at position 32) since Carrier is inherited from Object directly. In principle, it is enough to add the following code before the line that casts Carrier to String:
1 |
long carrierClassAddress = normalize( unsafe.getInt(carrier, 4L) );
|
2 |
long stringClassAddress = normalize( unsafe.getInt( "" , 4L) );
|
3 |
unsafe.putAddress(carrierClassAddress + 32 , stringClassAddress);
|
Now cast works fine. Nevertheless, this transformation is not correct and violates VM contracts. More careful approach should include more steps:
- Position 32 in Carrier class actually contains a pointer to Carrier class itself, so this pointer should be shifted to position 36, not simply overwritten by the pointer to the String class.
- Since Carrier is now inherited from String, final markers in String class should be removed.
Conclusion
sun.misc.Unsafe provides almost unlimited capabilities for exploring and modification of VM’s runtime data structures. Despite the fact that these capabilities are almost inapplicable in Java development itself, Unsafe is a great tool for anyone who want to study HotSpot VM without C++ code debugging or need to create ad hoc profiling instruments.
分享到:
相关推荐
based guide, where each chapter focuses on the complete implementation of a real-world scenario, the commonly occurring challenges in each scenario has also discussed, along with tips and tricks and ...
features tips and tricks that an experienced shader programmer will benefit from. As with Direct3D ShaderX, Javier Izquierdo Villagrán (nurbs1@jazzfree.com) prepared the drafts for the ...
《ShaderX2:Shader Programming Tips & Tricks with DirectX 9》是一本由Wolfgang F. Engel编辑的专业书籍,由Wordware Publishing出版。本书主要介绍了使用DirectX 9进行着色器编程的各种技巧与窍门,适合游戏开发...
features tips and tricks that an experienced shader programmer will benefit from. As with Direct3D ShaderX, Javier Izquierdo Villagrán (nurbs1@jazzfree.com) prepared the drafts for the ...
Shaderx 2, Shader Programming Tips and Tricks with DirectX ,ShaderX
Java Reflection in Action is unique in presenting a clear account of all the cool things you can do with reflection, and at the same time providing the sound conceptual basis that developers need to ...
Best practice and tips & tricks to write scientific papers in LaTeX, with figures generated in Python or Matlab.zip
Java Reflection in Action is unique in presenting a clear account of all the cool things you can do with reflection, and at the same time pro- viding the sound conceptual basis that developers need to...
本书《ShaderX2: Shader Programming Tips and Tricks with DirectX 9.0》由Wolfgang F. Engel编辑,Wordware Publishing, Inc.出版,首次发行于2003年10月25日。这本书的主旨在于分享在微软的DirectX 9.0环境下进行...
Write any Java program logic with strategies, tips, and tricks Leverage advanced topics in Java collections to solve Java-related problems Understand and use objects, classes, methods, and functions ...
who are all leading Java performance and Java HotSpot VM experts, help you improve performance by using modern software engineering practices, avoiding common mistakes, and applying tips and tricks ...
You will begin by discovering what regular expressions are and how they work with Java. This easy-to-follow guide is a ... Finally, you will master tips, tricks, and best practices in regex with Java
ods html (styleattrs colwidths=(2in 1in 1in)); ``` 通过上述技巧,用户可以轻松地利用ODS创建既美观又专业的报告。无论是对于初学者还是经验丰富的SAS用户来说,掌握这些技能都将大有裨益。
TRICKS OF THE JAVA™ PROGRAMMING GURUS
《ShaderX2 - Tips_and_Tricks_with_DirectX_9》是关于DirectX 9图形编程的一本技术文集,汇集了众多专家的经验与技巧,旨在帮助开发者更好地理解和利用DirectX 9的强大功能,实现更高效、更具表现力的图形渲染效果...
"Java Crash Course" contains a multitude of tips and tricks, examples and exercises you can do to grow your Java programming skills to unprecedented levels. We chose the content of this book carefully...
Section I—Geometry Manipulation Tricks 1 Using Vertex Shaders for Geometry Compression 3 Dean Calver Using Lookup Tables in Vertex Shaders 13 Carsten Wenzel Terrain Geomorphing in the Vertex Shader ...
### Tricks and Tips with NIO Using the Grizzly Framework #### 目标与背景 在本次演讲中,我们将分享我们在开发Project Grizzly NIO框架过程中学到的一些技巧和窍门。Project Grizzly是一个利用Java NIO(非...