Description:
Recently we tested wire compression using connector/j and noticed potential memory leak with inflater, which causes GC. The following is the theory (in src/com/mysql/jdbc/CompressedInputStream.java).
Look at the code in methodCompressedInputStream.getNextPacketFromServer():
...
try {
this.inflater.reset();
} catch (NullPointerException npe) {
this.inflater = new Inflater();
}
this.inflater.setInput(compressedBuffer);
try {
this.inflater.inflate(uncompressedData);
} catch (DataFormatException dfe) {
throw new IOException(
"Error while uncompressing packet from server.");
}
this.inflater.end();
...
It re-allocates or resets the inflater, does the uncompression, and then calls end(). Unfortunately,inflater.end() actually completely shuts down the inflater and reclaims its native buffer. So, next time thegetNextPacketFromServer() method is called (I assume it is called very frequently?), inflater.reset() will throw a NullPointerException given the inflater had been reset and the address to its native buffer is 0.
So a new Inflater is created for every call to getNextPacketFromServer(), which can definitely explain why we have so many.
How to repeat:
Turn on wire compression, and monitor the memory usage, or check the # of inflater object.
Suggested fix:
A solution could be not to call inflater.end() fromgetNextPacketFromServer(). This way, reset() will actually manage to reset the inflater and we might avoid constantly allocating new ones.