Java Write directly to memory
You have been told a lot that you can’t manage memory in Java. Well, it has changed since HotSpot release of the Java VM. There is a way to directly allocate and deallocate memory as well as write and read it… Of course we are talking about the JVM memory where the Java program runs. In this tutorial we are going to show you codes that deal with this topic.
1. Obtaining the sun.misc.Unsafe object
To work directly on a memory in Java you need to have a sun.misc.Unsafe class instance. This class delivers a bunch of methods to work with the JVM memory directly. Obtaining this object is quite easy, here is a simple helper method that returns the Unsafe class instance.
private static Unsafe getUnsafe() throws Exception { // Get the Unsafe object instance Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (sun.misc.Unsafe) field.get(null);
2. Writing and reading bytes directly from memory
Reading and writing bytes to the memory is very simple when you have the Unsafe object reference. All you need to do is allocating memory by calling the allocateMemory method which returns the allocated memory address. To write a byte value just call the putAddress method or the putByte method of the sun.misc.Unsafe class. To read a byte value you need to call the getAddress or getByte method. Look at the following example where we show how to write and read bytes.
public static void showBytes() { try { Unsafe unsafe = getUnsafe(); // Writing to a memory - MAX VALUE Byte byte value = Byte.MAX_VALUE; long bytes = 1; // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); // Write value to the allocated memory unsafe.putAddress(memoryAddress, value); // or putByte // Output the value written and the memory address System.out.println("[Byte] Writing " + value + " under the " + memoryAddress + " address."); long readValue = unsafe.getAddress(memoryAddress); // or getByte // Output the value from System.out.println("[Byte] Reading " + readValue + " from the " + memoryAddress + " address."); // C style! Release the Kraken... Memory!! :) unsafe.freeMemory(memoryAddress); } catch (Exception e) { e.printStackTrace();
Using getAddress and putAddress methods is safe for bytes but if you want to read and write Long values it is safer not to use these methods due to the fact that getAddress method returns 32-bit long variable (if you will try to store read a value which is greater than 4294967295, represented as 111111111111111111111111111111 you might not succeed).
3. Writing and reading Long values directly from memory
If you want to read and write Long values you can achieve it the same way as before but you need to use the putLong and getLong methods of the sun.misc.Unsafe class. See the above snippet.
private static void showLong() { try { Unsafe unsafe = getUnsafe(); // Writing to a memory - MAX VALUE of Long long value = Long.MAX_VALUE; long bytes = Long.SIZE; // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); // Write value to the allocated memory unsafe.putLong(memoryAddress, value); // Output the value written and the memory address System.out.println("[Long] Writing " + value + " under the " + memoryAddress + " address."); // Read the value from the memory long readValue = unsafe.getLong(memoryAddress); // Output the value from System.out.println("[Long] Reading " + readValue + " from the " + memoryAddress + " address."); // C style! Release the Kraken... Memory!! :) unsafe.freeMemory(memoryAddress); } catch (Exception e) { e.printStackTrace();
4. Important! Deallocating memory.
It is very important to run the memory deallocation method – freeMemory of the sun.misc.Unsafe class. The below snippet shows what happens when you don’t free used memory. This code starts 100 threads where each of them loops 1000000 times allocating memory, writing and reading a random Long value.
public static void showDontFreeMemory() { for (int t = 0; t < 100; t++) { new Thread() { public void run() { System.out.println("Thread " + Thread.currentThread().getName() + " start!"); for (int i = 0; i < 1000000; i++) { try { Unsafe unsafe = getUnsafe(); // Writing random Long to a memory long value = new Random().nextLong(); long bytes = Long.SIZE; // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); // Write value to the allocated memory unsafe.putLong(memoryAddress, value); // Read the value from the memory long readValue = unsafe.getLong(memoryAddress); // Always free the memory !! // ... FIXME: deallocate the memory used } catch (Exception e) { e.printStackTrace(); System.out.println("Thread " + Thread.currentThread().getName() + " stop!"); }; }.start();
When you run the above method you’ll end up with the java.lang.OutOfMemoryError thrown by the allocateMemory method.
Exception in thread "Thread" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) ...
You will receive the above Exception when you will try to allocate too much memory as well. It will happen when you will try to run the below snippet.
public static void showAllocateTooMuch() { try { Unsafe unsafe = getUnsafe(); long bytes = Integer.MAX_VALUE; // It's way too much memory!! // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); } catch (Exception e) { e.printStackTrace();
These are only the basics of direct memory access in Java. You will find the complete running example below.
package com.itcuties; import java.lang.reflect.Field; import java.util.Random; import sun.misc.Unsafe; /** * How to write directly to a memory. * * @author itcuties * */ public class test { public static void main(String[] args) { // Uncomment to show how to read/write bytes //showBytes(); // Uncomment to show how to read/write long values showLong(); // Uncomment to show what happens when you don't free the memory // showDontFreeMemory(); // Uncomment to show how does program run while the memory is being // deallocated // showFreeMemory(); // Uncomment to show what happens when you allocate to much memory showAllocateTooMuch(); /** * This method shows how to read/write bytes to the memory. */ public static void showBytes() { try { Unsafe unsafe = getUnsafe(); // Writing to a memory - MAX VALUE Byte byte value = Byte.MAX_VALUE; long bytes = 1; // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); // Write value to the allocated memory unsafe.putAddress(memoryAddress, value); // or putByte // Output the value written and the memory address System.out.println("[Byte] Writing " + value + " under the " + memoryAddress + " address."); long readValue = unsafe.getAddress(memoryAddress); // or getByte // Output the value from System.out.println("[Byte] Reading " + readValue + " from the " + memoryAddress + " address."); // C style! Release the Kraken... Memory!! :) unsafe.freeMemory(memoryAddress); } catch (Exception e) { e.printStackTrace(); /** * This method show how to read/write Long values to the memory. */ private static void showLong() { try { Unsafe unsafe = getUnsafe(); // Writing to a memory - MAX VALUE of Long long value = Long.MAX_VALUE; long bytes = Long.SIZE; // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); // Write value to the allocated memory unsafe.putLong(memoryAddress, value); // Output the value written and the memory address System.out.println("[Long] Writing " + value + " under the " + memoryAddress + " address."); // Read the value from the memory long readValue = unsafe.getLong(memoryAddress); // Output the value from System.out.println("[Long] Reading " + readValue + " from the " + memoryAddress + " address."); // C style! Release the Kraken... Memory!! :) unsafe.freeMemory(memoryAddress); } catch (Exception e) { e.printStackTrace(); /** * This method show what happens when you don't deallocate memory. We start * 100 threads where each one is allocating memory for a Long value and * writes it 1000000 times without deallocating memory. */ public static void showDontFreeMemory() { for (int t = 0; t < 100; t++) { new Thread() { public void run() { System.out.println("Thread " + Thread.currentThread().getName() + " start!"); for (int i = 0; i < 1000000; i++) { try { Unsafe unsafe = getUnsafe(); // Writing random Long to a memory long value = new Random().nextLong(); long bytes = Long.SIZE; // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); // Write value to the allocated memory unsafe.putLong(memoryAddress, value); // Read the value from the memory long readValue = unsafe.getLong(memoryAddress); // Always free the memory !! // ... FIXME: deallocate the memory used } catch (Exception e) { e.printStackTrace(); System.out.println("Thread " + Thread.currentThread().getName() + " stop!"); }; }.start(); /** * This method code shows how you should properly allocate and deallocate * memory. We start 100 threads where each one is allocating memory for a * Long value and writes it 1000000 times with deallocating memory. */ public static void showFreeMemory() { for (int t = 0; t < 100; t++) { new Thread() { public void run() { System.out.println("Thread " + Thread.currentThread().getName() + " start!"); for (int i = 0; i < 1000000; i++) { try { Unsafe unsafe = getUnsafe(); // Writing random Long to a memory long value = new Random().nextLong(); long bytes = Long.SIZE; // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); // Write value to the allocated memory unsafe.putLong(memoryAddress, value); // Read the value from the memory long readValue = unsafe.getLong(memoryAddress); // Always free the memory !! unsafe.freeMemory(memoryAddress); } catch (Exception e) { e.printStackTrace(); System.out.println("Thread " + Thread.currentThread().getName() + " stop!"); }; }.start(); /** * This method shows what happens when you try to allocate to much memory at * a time. */ public static void showAllocateTooMuch() { try { Unsafe unsafe = getUnsafe(); long bytes = Integer.MAX_VALUE; // It's way too much memory!! // Allocate given memory size long memoryAddress = unsafe.allocateMemory(bytes); } catch (Exception e) { e.printStackTrace(); /** * Get the Unsafe object instance. * * @return * @throws Exception */ private static Unsafe getUnsafe() throws Exception { // Get the Unsafe object instance Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (sun.misc.Unsafe) field.get(null);
From:一号门
Next:Donate to Charity
COMMENTS