1. верхний предел распределения массива
Размер массива в Java ограничен, потому что он использует тип Int в качестве индекса массива. Это означает, что вы не можете подать заявку на массивы, которые превышают размер integer.max_value (2^31-1). Это не означает, что верхний предел вашего приложения памяти составляет 2 г. Вы можете подать заявку на массив больших типов. например:
Кода -копия выглядит следующим образом:
final Long [] ar = new Long [Integer.max_Value];
Это выделит 16 г -8 байтов. это просто общие правила, конкретное распределение зависит от фактической ситуации).
К сожалению, в Java, из -за ограничения типов элементов массива, в эксплуатации памяти будет более хлопотно. Когда дело доходит до эксплуатационных массивов, Bytebuffer должен быть наиболее полезным классом, который предоставляет методы чтения и написания различных типов Java. Его недостаток заключается в том, что тип целевого массива должен быть байт [], что означает, что максимальный кэш памяти, который вы выделяете, может быть 2G.
2. Используйте все массивы в качестве массивов для работы
Предполагая, что память 2G сейчас далеко не достаточно для нас, это нормально, если это 16 г. Мы назначили длинный [], но мы хотим управлять им как массив байтов. В Java мы должны попросить о помощи у программистов C - sun.misc.unsafe. Этот класс имеет два набора методов: getn (Object, Offset), этот метод должен получить значение указанного типа из позиции, где смещение объекта смещено и возвращает его Метод PUTN (объект, смещение, значение) состоит в том, чтобы написать значение в положение смещения объекта.
К сожалению, эти методы могут получить или устанавливать значения определенного типа. Если вы копируете данные из массива, вам также нужен другой метод небезопасного, Copymemory (srcobject, srcoffset, destobject, destoffet, count). Это работает аналогично System.Arraycopy, но он копирует байты, а не элементы массива.
Чтобы получить доступ к данным массива через sun.misc.unsafe, вам нужно две вещи:
1. Смещение данных в объекте массива
2. Смещение копированных элементов в данных массива
Как и другие объекты Java, у Arrays есть заголовок объекта, который хранится перед фактическими данными. Длина этого заголовка может быть получена методом небезопасного. Размер элемента массива может быть получен с помощью метода небезопасно. Это означает, что если вы хотите получить доступ к NTH -элементу Type T, ваше смещение должно быть ArrayOffSet+N*ArrayScale.
Давайте напишем простой пример. Мы распределяем длинный массив и обновляем несколько байтов внутри него. Мы обновляем последний элемент до -1 (0xfffffffffffffffffffffffffffff), а затем очищаем все байты этого элемента один за другим.
Кода -копия выглядит следующим образом:
окончательный длинный [] ar = new Long [1000];
final int index = ar.length - 1;
ar [index] = -1; // fffffffffff
System.out.println ("до изменения =" + long.tohexstring (ar [index]));
для (длинный i = 0; i <8; ++ i)
{
unceabe.putbyte (ar, longarrayoffset + 8l * index + i, (byte) 0);
System.out.println ("После изменения: i =" + i + ", val =" + long.tohexstring (ar [index]));
}
Если вы хотите запустить приведенный выше пример, вы должны добавить следующий статический блок кода в свой тестовый класс:
Кода -копия выглядит следующим образом:
Частный статический финал небезопасно небезопасно;
статический
{
пытаться
{
Field Field = uncefe.class.getDeclaredfield ("TheUnsafe");
Field.SetAccessible (true);
небезопасно = (небезопасно) Field.get (null);
}
Поймать (исключение E)
{
бросить новое runtimeexception (e);
}
}
Частный статический финал Longarrayoffset = небезопасно. Arraybaseoffset (long []. Class);
Результатом вывода:
Кода -копия выглядит следующим образом:
Перед изменением = ffffffffffffffffffff
После изменения: i = 0, val = ffffffffffffff00
После изменения: i = 1, val = ffffffffffff0000
После изменения: i = 2, val = ffffffffff000000
После изменения: i = 3, val = ffffffff00000000
После изменения: i = 4, val = ffffff00000000000
После изменения: i = 5, val = ffff0000000000000
После изменения: i = 6, val = ff000000000000000
После изменения: i = 7, val = 0
3. Распределение памяти sun.misc.unsafe
Как упоминалось выше, в чистой Java размер памяти, который мы можем выделить, ограничен. Это ограничение было установлено в первоначальной версии Java, и в то время люди не осмелились делиться несколькими G памяти, подобной этой. Но теперь это эпоха больших данных, и нам нужно больше памяти. В Java есть два способа получить больше памяти:
1. Выделите много небольших кусков памяти, а затем логически используйте их в качестве непрерывного большого количества памяти.
2. Используйте Sun.misc.unsafe.allcatememory (Long), чтобы распределить память.
Первый метод немного более интересен с точки зрения алгоритмов, поэтому давайте посмотрим на второй метод.
sun.misc.unsafe предоставляет набор методов для распределения, переоборудования и отпускания памяти. Они очень похожи на метод C Malloc/Free:
1. Второй небезопасность. Алокатемемория (большие размеры)-Размещайте кусок пространства памяти. Эта часть памяти может содержать нежелательные данные (не автоматически очищенные). Если распределение не удается, будет брошено исключение Java.lang.outofmemoryerror. Он возвращает ненулевой адрес памяти (см. Описание ниже).
2. Unsafe.Reallocatememory (длинный адрес, длинный размер)-РЕАЛИКАТАЦИЯ ПЕРЕДАКИ памяти и копируйте данные из старого буфера памяти (где адрес указывает) в недавно выделенный блок памяти. Если адрес равен 0, этот метод имеет тот же эффект, что и Allocatememory. Возвращает адрес нового буфера памяти.
3. unsafe.freememory (длинный адрес) -free буфер памяти, сгенерированный предыдущими двумя методами. Если адрес 0, ничего не делай.
Память, выделяемая этими методами, должна использоваться в режиме, называемом единым адресом регистра: небезопасно предоставляет набор методов, которые принимают только один параметр адреса (в отличие от режима двойного регистра, им требуется объект и смещение смещения). Память, выделенная таким образом, может быть больше, чем то, что вы настраиваете в параметрах Java от -xmx.
Примечание. Память, выделенная небезопасным, не может быть собрана мусором. Вы должны относиться к нему как к обычному ресурсу и самостоятельно управлять им.
Вот пример использования небезопасного. Allocatememory для распределения памяти, а также проверяет, является ли весь буфер памяти читаемым и подлежащим записи:
Кода -копия выглядит следующим образом:
окончательный int size = integer.max_value / 2;
Окончательный длинный addr = небезопасно. Allocatememory (размер);
пытаться
{
System.out.println ("небезопасной адрес =" + addr);
для (int i = 0; i <size; ++ i)
{
небезопасно.putbyte (addr + i, (байт) 123);
if (uncefe.getbyte (addr + i)! = 123)
System.out.println ("Не удастся на offset =" + i);
}
}
Окончательно
{
небезопасно.freememory (addr);
}
Как вы можете видеть, используя sun.misc.unsafe, вы можете написать очень общий код доступа к памяти: независимо от того, какая память выделена на Java, вы можете читать и написать любой тип данных по желанию.