我有一些旧代码直到最近才工作,但现在似乎很糟糕,因为它在使用 OpenJDK 6 而不是 Java SE 6 的新服务器上运行。
问题似乎围绕着 JAI.create。我有 jpeg 文件,我将其缩放并转换为 png 文件。这段代码过去工作时没有泄漏,但现在已经转移到运行 OpenJDK 的机器上,文件描述符似乎永远不会关闭,并且我看到越来越多的 tmp 文件累积在服务器上的 tmp 目录中。这些不是我创建的文件,所以我假设是 JAI 执行的。
另一个原因可能是新服务器上的堆大小较大。如果 JAI 在 Finalize 时进行清理,但 GC 发生的频率较低,那么可能会因此而导致文件堆积。减少堆大小不是一个选择,而且我们似乎遇到了与增加 ulimit 无关的问题。
这是我运行此命令时泄漏的文件的示例:
/tmp/imageio7201901174018490724.tmp
一些代码:
// Processor is an internal class that aggregates operations
// performed on the image, like resizing
private byte[] processImage(Processor processor, InputStream stream) {
byte[] bytes = null;
SeekableStream s = null;
try {
// Read the file from the stream
s = SeekableStream.wrapInputStream(stream, true);
RenderedImage image = JAI.create("stream", s);
BufferedImage img = PlanarImage.wrapRenderedImage(image).getAsBufferedImage();
// Process image
if (processor != null) {
image = processor.process(img);
}
// Convert to bytes
bytes = convertToPngBytes(image);
} catch (Exception e){
// error handling
} finally {
// Clean up streams
IOUtils.closeQuietly(stream);
IOUtils.closeQuietly(s);
}
return bytes;
}
private static byte[] convertToPngBytes(RenderedImage image) throws IOException {
ByteArrayOutputStream out = null;
byte[] bytes = null;
try {
out = new ByteArrayOutputStream();
ImageIO.write(image, "png", out);
bytes = out.toByteArray();
} finally {
IOUtils.closeQuietly(out);
}
return bytes;
}
我的问题是:
- 有人遇到过这个问题并解决了吗?由于创建的 tmp 文件不是我的,我不知道它们的名字是什么,因此无法对它们做任何事情。
- 用于调整图像大小和重新格式化图像的库有哪些?我听说过 Scalr - 还有什么我应该研究的吗?
我宁愿此时不重写旧代码,但如果没有其他选择......
Thanks!
只是对临时文件/终结器问题的评论,现在您似乎已经解决了问题的根源(评论太长,所以我将其作为答案发布...:-P):
临时文件是由 ImageIO 创建的FileCacheImageInputStream
。每当您调用时都会创建这些实例ImageIO.createImageInputStream(stream)
和useCache http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html#getUseCache%28%29标志是true
(默认)。您可以将其设置为false
禁用磁盘缓存,但以内存缓存为代价。当您有一个很大的堆时,这可能有意义,但如果您正在处理非常大的图像,则可能没有意义。
我还认为您对终结器问题的看法(几乎)是正确的。您会发现以下“finalize”方法FileCacheImageInputStream
(Sun JDK 6/1.6.0_26):
protected void finalize() throws Throwable {
// Empty finalizer: for performance reasons we instead use the
// Disposer mechanism for ensuring that the underlying
// RandomAccessFile is closed/deleted prior to garbage collection
}
类的构造函数中有一些非常“有趣”的代码,它们在实例完成时设置自动流关闭和处置(如果客户端代码忘记这样做)。这在 OpenJDK 实现中可能有所不同,至少看起来有点 hacky。目前我也不清楚我们正在谈论的“性能原因”到底是什么......
无论如何,它似乎在呼唤close
on the ImageInputStream
实例,就像您现在所做的那样,将正确关闭文件描述符并删除临时文件。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)