Bug #78106 Potential memory leak with inflater
Submitted: 17 Aug 2015 14:32 Modified: 2 Sep 2015 18:13
Reporter: Calvin Sun Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:5.1.36 OS:Any
Assigned to: Alexander Soklakov CPU Architecture:Any

[17 Aug 2015 14:32] Calvin Sun
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.
[18 Aug 2015 7:25] Alexander Soklakov
Verified as described.
[2 Sep 2015 18:13] Daniel So
Added the following entry to the Connector/J 5.1.37 changelog:

"The method methodCompressedInputStream.getNextPacketFromServer() has been refactored to reduce memory use and garbage collection efforts caused by the use of the inflater."