Рубрики
Без рубрики

Java – Запись непосредственно в память

– Java – Запись непосредственно в память

Вам много раз говорили, что вы не можете управлять памятью на Java. Ну, это изменилось с момента выпуска виртуальной машины Java. Существует способ прямого выделения и освобождения памяти, а также ее записи и чтения… Конечно, мы говорим о памяти JVM, в которой выполняется программа Java. В этом уроке мы покажем вам коды, которые касаются этой темы.

1. Получение солнца. разное. Небезопасный объект

Для работы непосредственно с памятью в Java вам необходимо иметь sun.misc. Небезопасный экземпляр класса. Этот класс предоставляет множество методов для непосредственной работы с памятью JVM. Получить этот объект довольно просто, вот простой вспомогательный метод, который возвращает экземпляр небезопасного класса.

  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. Запись и чтение байтов непосредственно из памяти

Чтение и запись байтов в память очень просты, когда у вас есть ссылка на небезопасный объект. Все, что вам нужно сделать, это выделить память, вызвав метод выделить память , который возвращает адрес выделенной памяти. Чтобы записать значение в байтах, просто вызовите метод put Address или putbytes метода sun.разное. Небезопасно класс. Чтобы прочитать значение в байтах, вам нужно вызвать Получить адрес или Метод getByte . Посмотрите на следующий пример, где мы показываем, как записывать и считывать байты.

  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();
    }
  }

Использование Получить адрес и поместить адрес методы безопасны для байтов, но если вы хотите читать и писать Длинные значения безопаснее не использовать эти методы из-за того, что Метод getAddress возвращает 32-разрядную длинную переменную (если вы попытаетесь сохранить прочитанное значение, которое больше, чем 4294967295 , представленный в виде 111111111111111111111111111111111111111111111111111111111111

3. Запись и чтение длинных значений непосредственно из памяти

Если вы хотите читать и записывать длинные значения, вы можете сделать это так же, как и раньше, но вам нужно использовать put Long и получить длинные методы вс.разное. Небезопасно класс. Смотрите приведенный выше фрагмент.

  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. Важный! Освобождающая память.

Очень важно запустить метод освобождения памяти – Свободная память из sun.разное. Небезопасно класс. Приведенный ниже фрагмент показывает, что происходит, когда вы не освобождаете используемую память. Этот код запускает 100 потоков, где каждый из них зацикливается 1000000 раз, выделяя память, записывая и считывая случайное длинное значение.

  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();
    }
  }

Когда вы запустите описанный выше метод, вы получите java.lang. Ошибка OutOfMemoryError , вызванная методом выделения памяти .

Exception in thread "Thread" java.lang.OutOfMemoryError
        at sun.misc.Unsafe.allocateMemory(Native Method)
        ...

Вы получите вышеупомянутое исключение, когда также попытаетесь выделить слишком много памяти. Это произойдет, когда вы попытаетесь запустить приведенный ниже фрагмент.

  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();
     }
  }

Это только основы прямого доступа к памяти в Java. Ниже вы найдете полный пример выполнения.

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);
  }

}

Скачать Исходный Код

Оригинал: “https://mkyong.com/java/java-write-directly-to-memory/”