чрезмерное использование памяти Java - PullRequest
3 голосов
/ 08 июня 2011

В моем проекте я постоянно сжимаю небольшие блоки данных.Теперь я узнаю, что 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 ]

7 голосов
/ 19 декабря 2013

Что ж, Фолькерт ван Хойсден решил свою проблему, но в итоге:

В начале compress(byte [] in) -метода мы создаем java.util.zip.Deflater.

Мы используем Deflater чтобы что-то сделать, и тогда мы оставляем compress() -метод.Мы теряем нашу ссылку на deflater -вариант.На данный момент Deflater больше не используется и ожидает уничтожения сборщиком мусора.

Deflater выделяет обе память кучи Java и C/ C ++ / собственная память кучи .Собственная кучная память, выделенная 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()).

0 голосов
/ 08 июня 2011

Что ж, мне кажется, что в коде нет утечки памяти, поэтому на самом деле кажется, что виртуальная машина не является байтовыми массивами 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);
...