Чрезмерное использование памяти Java
В моем проекте я постоянно сжимаю небольшие блоки данных. Теперь я обнаружил, что jvm увеличивается до 6 ГБ оперативной памяти (резидентная (RES) RAM, не разделяемая или виртуальная или около того) и затем умирает из-за нехватки памяти. Это как если бы сборщик мусора никогда не работал или около того. Я вытащил соответствующий код и вставил его ниже. Когда я запускаю его (java6, 32-разрядная версия Linux), он увеличивается до 1 ГБ ОЗУ. Кто-нибудь получил идею, как уменьшить использование памяти?
import java.util.Random;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
class test {
int blockSize = 4096;
Random r = new Random();
public test() throws Exception {
blockSize = 4096;
byte [] data = new byte[blockSize];
for(int index=0; index<blockSize; index++)
data[index] = (byte)r.nextInt();
for(long cnt=0; cnt<1000000; cnt++) {
byte [] result = compress(data);
if (result != null)
data[0] = result[0];
}
}
byte [] compress(byte [] in) {
assert in.length == blockSize;
Deflater compresser = new Deflater();
compresser.setInput(in);
compresser.finish();
byte [] out = new byte[in.length];
int outLen = compresser.deflate(out);
if (outLen < blockSize) {
byte [] finalOut = new byte[outLen];
System.arraycopy(out, 0, finalOut, 0, outLen);
return finalOut;
}
return null;
}
public static void main(String [] args) throws Exception {
new test();
}
}
2 ответа
Что ж, Фолькерт ван Хеусден решил свою проблему, но подведу итог:
В начале compress(byte [] in)
-метод, мы создаем java.util.zip.Deflater
,
Мы используем Deflater
сделать что-то, а затем мы оставляем compress()
-метод. Мы теряем нашу ссылку на deflater
-переменный. На данный момент, Deflater
больше не используется, и его ожидает сборщик мусора.
Deflater
выделяет как кучу памяти Java, так и кучную память C/C++/native. Собственная память кучи, выделенная Deflater
, пройдет до Deflater.finalize
-метод вызывается сборщиком мусора. Если сборщик мусора работает недостаточно быстро (может быть, много свободной памяти кучи Java), мы можем исчерпать кучу памяти C / C++. Если это произойдет, мы получим ошибки "Недостаточно памяти".
Отчет об ошибке Oracle JDK-4797189, вероятно, связан. Он содержит фрагмент кода, который иллюстрирует и воспроизводит проблему:
public class Bug {
public static void main( String args[] ) {
while ( true ) {
/* If ANY of these two lines is not commented, the JVM
runs out of memory */
final Deflater deflater = new Deflater( 9, true );
final Inflater inflater = new Inflater( true );
}
}
}
Решение состоит в том, чтобы освободить ресурсы, когда вы закончите, позвонив Deflater.end()
-метод (или Inflater.end()
).
Что ж, мне кажется, что в коде нет утечки памяти, поэтому на самом деле кажется, что виртуальная машина не является байтовыми массивами GC-ing.
"Кто-нибудь получил идею, как уменьшить использование памяти?"
Ну я бы попробовал с
byte firstByteOfDataWhichIsCompressedAndThenUncompressed(byte [] in) { ... }
который конкретно возвращает первый байт несжатого массива, а не весь массив. Я знаю, это ужасное название метода, и я надеюсь, что вы найдете лучший.
Следующий код
for(long cnt=0; cnt<1000000; cnt++) {
byte [] result = compress(data);
if (result != null)
data[0] = result[0];
}
станет
for(long cnt=0; cnt<1000000; cnt++)
data[0] = firstByteOfDataWhichIsCompressedAndThenUncompressed(data);