2013-08-29 231 views
3

我有一个工作,直到最近,一些旧的代码,但现在似乎BARF它运行使用的OpenJDK 6而不是Java SE的6JAI创建似乎离开文件描述符开放

这个问题似乎在新服务器上围绕JAI.create。我有我缩放并转换为PNG文件的jpeg文件。这段代码过去没有任何泄漏,但现在移动到了运行OpenJDK的盒子,文件描述符似乎永远不会关闭,并且我看到越来越多的tmp文件在服务器上的tmp目录中累积。这些不是我创建的文件,所以我认为它是JAI。

另一个原因可能是新服务器上的堆大小较大。如果JAI清理完成,但是GC发生的频率较低,那么也许这些文件因此而堆积如山。减少堆大小不是一种选择,我们似乎与增加限制有关的不相关问题。

这里是当我运行这个泄漏的文件的一个例子:

/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; 
} 

我的问题是:

  1. 有没有人遇到这一点,解决了吗?由于创建的tmp文件不是我的,我不知道他们的名字是什么,因此不能对它们做任何事情。
  2. 调整和重新格式化图像的选择库有哪些?我听说过斯卡尔 - 我应该看看什么?

我宁可不要在这个时候rewite的旧代码,但如果没有别的选择......

谢谢!

回答

0

找到了!

所以流被另一个流中的代码不同的区域包裹:

iis = ImageIO.createImageInputStream(stream); 

进一步回落,流被关闭。

与Sun Java一起运行时,这似乎不会泄漏任何资源,但在使用Open JDK运行时似乎会导致泄漏。

我不确定这是为什么(我没有看过源代码来验证,虽然我有我的猜测),但这似乎正在发生。一旦我明确地关闭了包装流,一切都很好。

+0

所以在这个例子中,你明确地调用'iis.close()'并解决了这个问题? – rogerdpack

+0

@rogerdpack唉这是很久以前,我不记得我做了什么。我同意这似乎是答案的含义,我无法证实这是否确实是我所做的。抱歉。 – MrSilverSnorkel

4

只是对临时文件/终结器问题的评论,现在你似乎已经解决了问题的根源(对于评论太长了,所以我将它作为答案发布......:-P) :

临时文件由ImageIO的FileCacheImageInputStream创建。只要您致电ImageIO.createImageInputStream(stream)并且useCache标志为true(默认值),就会创建这些实例。您可以将其设置为false以禁用磁盘缓存,但会以内存缓存为代价。这可能是有意义的,因为你有一大堆,但如果你正在处理非常大的图像可能不会。

我也认为你是(几乎)正确的终结者问题。你会发现下面的'finalize'方法上FileCacheImageInputStream(太阳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实现中可能会有所不同,至少它看起来有点怪异。这也是我不清楚在什么“性能的原因,”我们正在谈论的那一刻...

在任何情况下,似乎在ImageInputStream实例调用close,因为你现在做的,会正确地关闭文件描述符删除临时文件。

+0

感谢您的输入。我承认我没有深入了解源代码。我也不知道缓存设置。非常感谢反馈。 – MrSilverSnorkel

+0

正确的你......已经完成并完成了。 – MrSilverSnorkel

+1

肯定有一些奇怪的事情发生,在我的例子中,JNA过于关闭处理。奇怪http://stackoverflow.com/q/38444752/32453 – rogerdpack