excessive memory use by java

雨燕双飞 提交于 2019-12-30 10:27:07

问题


In a project of mine I constantly compress little blocks of data. Now I find out that the jvm then grows to 6GB of ram (resident (RES) RAM, not shared or virtual or so) and then die because of out of memory. It is as if the garbage collector never runs or so. I've pulled out the relevant code and pasted it below. When I run it (java6, 32 bit linux) it grows to 1GB of ram. Anyone got an idea how to reduce the memory usage?

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

回答1:


Well, Folkert van Heusden solved his own problem, but to summarize:

Early in the compress(byte [] in)-method, we create a java.util.zip.Deflater.

We use the Deflater to do some stuff, and then we leave the compress()-method. We loose our reference to the deflater-variable. At this point, the Deflater is no longer in use, and is waiting to be killed by the garbage collector.

Deflater allocates both Java heap memory and C/C++/native heap memory. The native heap memory that are allocated by a Deflater, will be held until Deflater.finalize-method is called by the garbage collector. If the garbage collector doesn't run fast enough (there might be plenty free java heap memory), we can run out of C/C++ heap memory. If this happen, we will get "Out of memory"-errors.

The Oracle bug report JDK-4797189 is probably related. It contains a code snippet that illustrates and reproduces the problem:

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

The solution is to free the resources when you are finished by calling the Deflater.end()-method (or Inflater.end()).




回答2:


Well, It seems to me that there is no memory leak in the code, so it actually seems the VM is not GC-ing byte arrays.

"Anyone got an idea how to reduce the memory usage?"
Well, I would try with

byte firstByteOfDataWhichIsCompressedAndThenUncompressed(byte [] in) { ... }

which specifically returns the first byte of the uncompressed array, rather than the whole array. I know, it's a horrible method name, and I hope you will find a better one.

The following code

    for(long cnt=0; cnt<1000000; cnt++) {
        byte [] result = compress(data);
        if (result != null)
            data[0] = result[0];
    }

would become

    for(long cnt=0; cnt<1000000; cnt++)
        data[0] = firstByteOfDataWhichIsCompressedAndThenUncompressed(data);


来源:https://stackoverflow.com/questions/6274696/excessive-memory-use-by-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!