2013-10-01 2 views
4

Я пытаюсь понять, почему я получаю ошибку OOM, даже если байт-массив, который я инициализирую, плюс используемая в данный момент память меньше, чем максимальный размер кучи (1000 МБ) , Перед инициализацией массива я использую 373 МБ с 117 бесплатными. Когда я пытаюсь инициализировать массив, который занимает 371 МБ, я получаю сообщение об ошибке. Странная вещь заключается в том, что ошибка сохраняется до тех пор, пока я не выделяю 1.2G или более для JVM.Java OutOfMemoryError при распределении байта [] в пределах максимальной кучи

373 + 371 - 744, у меня все еще должно быть 256 МБ бесплатно, это приводит меня в бешенство. Во втором случае с использованием 920mb с 117 бесплатной инициализацией массив 918mb занимает не менее 2800 МБ.

Это как-то часть функции java? Если это так, обходной путь так, что что-то простое, как операция копирования массива, может быть выполнено менее чем в 3n памяти? (номер память имеет от выполнения и максимального размер кучи устанавливается с -Xmx)

test.java: 
byte iv[]; 
iv =new byte[32]; 
byte key[] = new byte[32]; 
new SecureRandom().nextBytes(iv); 
new SecureRandom().nextBytes(key); 
plaintext = FileUtils.readFileToByteArray(new File("sampleFile")); 
EncryptionResult out = ExperimentalCrypto.doSHE(plaintext, key, iv); 

ExperimentalCrypto.java: 
public static byte[] ExperimentalCrypto(byte[] input ,byte[] key, byte[]iv){ 
if(input.length%32 != 0){ 
int length = input.length; 
byte[] temp = null; 
System.out.println((input.length/32+1)*32/(1024*1024)); 
temp=new byte[(input.length/32+1)*32]; // encounter error here 
+1

Вы пытались использовать профилировщик, чтобы узнать, что использует память. –

+1

Как вы упомянули, 117 МБ были бесплатными, и если вы настроите массив из 371 МБ, он даст ошибку. вам нужно проанализировать, почему он показывал 117 бесплатно. Хотя ваш XMX составляет 1 ГБ, он может использоваться в другом месте в вашей программе. Используйте профилировщик, чтобы узнать, куда идет ваша память. –

+6

Одной из возможных причин является фрагментация кучи. См. Также: http://stackoverflow.com/questions/9286934/java-crashing-before-filling-up-heap-space – assylias

ответ

4

Типичных реализаций виртуальной машины Java разделить кучи Java на несколько частей, посвященных объекты с определенной жизнью. Выделение больших массивов обычно обходит этапы для более молодых объектов, поскольку эти области обычно меньше и позволяют избежать ненужного копирования. Таким образом, они попадут в пространство «старого поколения», для которого размер ⅔ не является необычным. Когда вы используете JVisualVM, я рекомендую установить плагин Visual GC, который может показать вам живое представление о различных областях памяти и их заполнении.

Вы можете использовать опции запуска -XX:MaxPermSize=… и -XX:MaxNewSize=…, чтобы уменьшить размеры областей для молодого и постоянного поколения и тем самым косвенно увеличить долю площади старого поколения, где будет выделен ваш массив.

+0

Имеет смысл, спасибо. Есть ли способ получить эти большие массивы, не требующие изменения аргументов vm? – kag0

+0

Возможно, вы можете использовать прямой 'ByteBuffer' вместо массива. Во многих местах их можно использовать в качестве альтернативы 'byte []'. http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#allocateDirect(int) – Holger

+0

Метод, над которым я работаю, предназначен для шифрования и, вероятно, должен возвращать байт [ ], поэтому в какой-то момент он будет использовать память 2n для байта [] (исходный ввод в вызывающем классе и массиве, который будет возвращен). Поэтому я не уверен, как избежать увеличения vm до 3n в процессе. Разве буфер не мог каким-то образом позволить мне работать с исходным массивом из вызывающего класса? – kag0

Смежные вопросы