Util: Fix memory leak in compressor (ticket #2471)

This commit is contained in:
zzz
2019-04-08 15:37:20 +00:00
parent 6aeb89ccd0
commit 7c7b0cb7fd
4 changed files with 47 additions and 5 deletions

View File

@ -168,6 +168,15 @@ public class ResettableGZIPInputStream extends InflaterInputStream {
}
}
/**
* Calls super.close(). May not be reused after this.
* @since 0.9.40
*/
public void destroy() throws IOException {
close();
super.close();
}
/**
* Does NOT call super.close(), as it cannot be reused if we do that.
* Broken before 0.9.20.

View File

@ -18,6 +18,7 @@ import java.util.zip.DeflaterOutputStream;
public class ResettableGZIPOutputStream extends DeflaterOutputStream {
/** has the header been written out yet? */
private boolean _headerWritten;
private boolean _footerWritten;
/** how much data is in the uncompressed stream? */
private long _writtenSize;
private final CRC32 _crc32;
@ -39,6 +40,7 @@ public class ResettableGZIPOutputStream extends DeflaterOutputStream {
_crc32.reset();
_writtenSize = 0;
_headerWritten = false;
_footerWritten = false;
}
private static final byte[] HEADER = new byte[] {
@ -61,6 +63,7 @@ public class ResettableGZIPOutputStream extends DeflaterOutputStream {
}
private void writeFooter() throws IOException {
if (_footerWritten) return;
// damn RFC writing their bytes backwards...
long crcVal = _crc32.getValue();
out.write((int)(crcVal & 0xFF));
@ -83,6 +86,16 @@ public class ResettableGZIPOutputStream extends DeflaterOutputStream {
System.out.print( Long.toHexString((int)((sizeVal >>> 24) & 0xFF)));
System.out.println();
}
_footerWritten = true;
}
/**
* Calls super.close(). May not be reused after this.
* @since 0.9.40
*/
public void destroy() throws IOException {
def.end();
super.close();
}
@Override
@ -90,6 +103,7 @@ public class ResettableGZIPOutputStream extends DeflaterOutputStream {
finish();
super.close();
}
@Override
public void finish() throws IOException {
ensureHeaderIsWritten();
@ -104,10 +118,12 @@ public class ResettableGZIPOutputStream extends DeflaterOutputStream {
_writtenSize++;
super.write(b);
}
@Override
public void write(byte buf[]) throws IOException {
write(buf, 0, buf.length);
}
@Override
public void write(byte buf[], int off, int len) throws IOException {
ensureHeaderIsWritten();

View File

@ -1,5 +1,6 @@
package net.i2p.util;
import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
/**
@ -32,13 +33,21 @@ public class ReusableGZIPInputStream extends ResettableGZIPInputStream {
}
return rv;
}
/**
* Release an instance back into the cache (this will reset the
* state)
*/
public static void release(ReusableGZIPInputStream released) {
if (ENABLE_CACHING)
_available.offer(released);
boolean cached;
if (ENABLE_CACHING) {
cached = _available.offer(released);
} else {
cached = false;
}
if (!cached) {
try { released.destroy(); } catch (IOException ioe) {}
}
}
private ReusableGZIPInputStream() { super(); }

View File

@ -2,6 +2,7 @@ package net.i2p.util;
//import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.concurrent.LinkedBlockingQueue;
@ -50,9 +51,16 @@ public class ReusableGZIPOutputStream extends ResettableGZIPOutputStream {
* state)
*/
public static void release(ReusableGZIPOutputStream out) {
boolean cached;
if (ENABLE_CACHING) {
out.reset();
if (ENABLE_CACHING)
_available.offer(out);
cached = _available.offer(out);
} else {
cached = false;
}
if (!cached) {
try { out.destroy(); } catch (IOException ioe) {}
}
}
private final ByteArrayOutputStream _buffer;