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. * Does NOT call super.close(), as it cannot be reused if we do that.
* Broken before 0.9.20. * Broken before 0.9.20.

View File

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

View File

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

View File

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