Skip to content

Commit

Permalink
close sejda-pdf#7: Prevent garbage collection of Encoder/Decoder obje…
Browse files Browse the repository at this point in the history
…cts during native encode/decode calls
  • Loading branch information
pbi-qfs committed Sep 2, 2020
1 parent 0b5d874 commit db476cc
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 3 deletions.
20 changes: 17 additions & 3 deletions src/main/java/com/luciad/imageio/webp/WebP.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ public static int[] decode(WebPDecoderOptions aOptions, byte[] aData, int aOffse
throw new IllegalArgumentException("Offset/length exceeds array size");
}

int[] pixels = decode(aOptions.fPointer, aData, aOffset, aLength, aOut, ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN));
int[] pixels;
try {
pixels = decode(aOptions.fPointer, aData, aOffset, aLength, aOut, ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN));
} finally {
aOptions.objectCanBeFinalized();
}

VP8StatusCode status = VP8StatusCode.getStatusCode(aOut[0]);
switch (status) {
case VP8_STATUS_OK:
Expand Down Expand Up @@ -83,13 +89,21 @@ public static int[] getInfo(byte[] aData, int aOffset, int aLength) throws IOExc
private static native int getInfo(byte[] aData, int aOffset, int aLength, int[] aOut);

public static byte[] encodeRGBA(WebPEncoderOptions aOptions, byte[] aRgbaData, int aWidth, int aHeight, int aStride) {
return encodeRGBA(aOptions.fPointer, aRgbaData, aWidth, aHeight, aStride);
try {
return encodeRGBA(aOptions.fPointer, aRgbaData, aWidth, aHeight, aStride);
} finally {
aOptions.objectCanBeFinalized();
}
}

private static native byte[] encodeRGBA(long aConfig, byte[] aRgbaData, int aWidth, int aHeight, int aStride);

public static byte[] encodeRGB(WebPEncoderOptions aOptions, byte[] aRgbaData, int aWidth, int aHeight, int aStride) {
return encodeRGB(aOptions.fPointer, aRgbaData, aWidth, aHeight, aStride);
try {
return encodeRGB(aOptions.fPointer, aRgbaData, aWidth, aHeight, aStride);
} finally {
aOptions.objectCanBeFinalized();
}
}

private static native byte[] encodeRGB(long aConfig, byte[] aRgbaData, int aWidth, int aHeight, int aStride);
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/luciad/imageio/webp/WebPDecoderOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ protected void finalize() throws Throwable {
fPointer = 0L;
}

/**
* Method to tell the Java Garbage collector that the object can now be released (and the native method
* is done working with the object).
*
* There is a finalizer in this object which clears the native assigned memory used by the WebP library
* during garbage collection. Without this method being properly called, garbage collection might happen
* before the native procedure has finished executing since the object is only forwarded via JNI by the
* fPointer and the underlying WebP library directly uses the complete object.
*
* This issue only manifests under high load because the time window between the native memory being used
* and the finalizer being called is very small.
*/
public void objectCanBeFinalized() {};

public int getCropHeight() {
return getCropHeight( fPointer );
}
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/luciad/imageio/webp/WebPEncoderOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ protected void finalize() throws Throwable {
fPointer = 0L;
}

/**
* Method to tell the Java Garbage collector that the object can now be released (and the native method
* is done working with the object).
*
* There is a finalizer in this object which clears the native assigned memory used by the WebP library
* during garbage collection. Without this method being properly called, garbage collection might happen
* before the native procedure has finished executing since the object is only forwarded via JNI by the
* fPointer and the underlying WebP library directly uses the complete object.
*
* This issue only manifests under high load because the time window between the native memory being used
* and the finalizer being called is very small.
*/
public void objectCanBeFinalized() {};

private static native long createConfig();

private static native void deleteConfig( long aPointer );
Expand Down

0 comments on commit db476cc

Please sign in to comment.