DeP*_*lle 4 java out-of-memory animated-gif javafx-2
我正在创建一个JavaFX 2.0应用程序,其中包含一个图像浏览器,当我OutOfMemoryError浏览几个GIF后遇到一些异常时,它应该能够显示动画GIF.我设法将相关代码隔离到"GifCrasher"应用程序中:
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import javafx.scene.image.Image;
public class GifCrash {
// Settings:
private static long waitTime = 100; // msec
private static ArrayList<File> imageFiles = new ArrayList<File>() {{
add(new File("thrillercat.gif"));
}};
// Other:
private static long totalSize = 0;
private static long gifsLoaded = 0;
public static void main(String[] args) throws Exception {
while(!Thread.currentThread().isInterrupted()) {
// Read gif file:
File imageFile = GifCrash.imageFiles.get((int) (GifCrash.gifsLoaded % GifCrash.imageFiles.size()));
InputStream iStream = new FileInputStream(imageFile);
Image image = new Image(iStream);
iStream.close();
// Display info:
GifCrash.gifsLoaded++;
GifCrash.totalSize += imageFile.length();
System.out.println("Loaded " + imageFile + " (" + imageFile.length() + " bytes)");
System.out.println("GifCount\t=\t" + GifCrash.gifsLoaded);
System.out.println("TotalSize\t=\t" + Math.round((double) GifCrash.totalSize / (1024 * 1024)) + " MBytes (" + GifCrash.totalSize + " bytes)");
System.out.println();
// Wait?
if (GifCrash.waitTime > 0) {
Thread.sleep(GifCrash.waitTime);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个简单的应用程序构建javafx Image对象而不实际对它们做任何事情,因此,据我所知,这些对象应该被垃圾收集.在示例应用程序中,我通过每次重新加载相同的GIF来模拟加载多个不同的GIF,而不是在某处缓存它(这样我就不必找到> 250MB的GIF文件).我还添加了一个可选waitTime参数,以确保垃圾收集器有机会释放一些内存.但是,使用动画GIF文件运行此应用程序imageFiles仍会在一段时间后产生OutOfMemoryError(在我加载大约250MBytes值的动画GIF之后).使用PNG文件运行应用程序完全没有问题,似乎动画GIF是唯一的问题.
这些是我用于测试的图像:thrillercat.gif和catdestroyer.png.这是我用thrillercat.gif运行应用程序时得到的(截断的)输出:
Loaded thrillercat.gif (1203120 bytes)
GifCount = 1
TotalSize = 1 MBytes (1203120 bytes)
Loaded thrillercat.gif (1203120 bytes)
GifCount = 2
TotalSize = 2 MBytes (2406240 bytes)
...
Loaded thrillercat.gif (1203120 bytes)
GifCount = 225
TotalSize = 258 MBytes (270702000 bytes)
Loaded thrillercat.gif (1203120 bytes)
GifCount = 226
TotalSize = 259 MBytes (271905120 bytes)
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.sun.javafx.iio.gif.GIFImageLoader2.decodePalette(GIFImageLoader2.java:288)
at com.sun.javafx.iio.gif.GIFImageLoader2.load(GIFImageLoader2.java:191)
at com.sun.javafx.iio.ImageStorage.loadAll(ImageStorage.java:294)
at com.sun.javafx.iio.ImageStorage.loadAll(ImageStorage.java:244)
at com.sun.javafx.tk.quantum.PrismImageLoader2.loadAll(PrismImageLoader2.java:107)
at com.sun.javafx.tk.quantum.PrismImageLoader2.<init>(PrismImageLoader2.java:41)
at com.sun.javafx.tk.quantum.QuantumToolkit.loadImage(QuantumToolkit.java:607)
at javafx.scene.image.Image.loadImage(Image.java:942)
at javafx.scene.image.Image.initialize(Image.java:722)
at javafx.scene.image.Image.<init>(Image.java:625)
at GifCrash.main(GifCrash.java:27)
Run Code Online (Sandbox Code Playgroud)
一如既往,我认为这是由于我的代码中的一些错误而不是错误,所以我在这里做错了什么?
如果这是一个错误,有没有办法解决它?即我需要能够在JavaFX窗口中显示大量的动画GIF(一次只能看到一个GIF).
谢谢!
只需使用Java 8,您的示例程序就可以使用Java 8版本.
我尝试了Java 7u45(OS X 10.8)(MacBook Air 2012,4gb ram)上的示例程序,并且在71次迭代后它一直耗尽内存.
而对于Java 8,程序在运行5000次迭代后永远不会耗尽内存:
Loaded /Users/lilyshard/dev/playfx/src/thriller-cat-o.gif (1203120 bytes)
GifCount = 10000
TotalSize = 11474 MBytes (12031200000 bytes)
Run Code Online (Sandbox Code Playgroud)
我没有解决方法让你的程序在Java 7u45上工作,并且不太可能将Java 8分支上的错误修复程序反向移植到JavaFX 2.2.有时,错误修复通过JavaFX问题跟踪器在用户请求上反向移植,但这种情况很少发生.
我的猜测是JavaFX 2.2 gif加载器中的一些错误已经修复,为Java 8版本做准备.