简体   繁体   English

JDK 1.7:由于POSIX信号量导致“打开文件太多”?

[英]JDK 1.7: “Too many open files” due to POSIX Semaphores?

I've looked through the other similar questions on SO, but they seem to be caused by other issues. 我已经查看了关于SO的其他类似问题,但它们似乎是由其他问题引起的。

First I made sure I judiciously closed all of my file handles, and then I used lsof -p <pid of java> to look at my list of files. 首先,我确保我明智地关闭了所有文件句柄,然后使用lsof -p <pid of java>来查看我的文件列表。

It stays pretty constant throughout my runtime but then periodically I will get about 10,000 entries listed in lsof like this: 它在整个运行时间内保持不变,但是我会定期在lsof列出大约10,000个条目,如下所示:

COMMAND   PID USER   FD     TYPE DEVICE  SIZE/OFF     NODE NAME
                                      ...
java    36809  smm *235r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *236r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *237r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *238r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *239r  PSXSEM              0t0          kcms00008FC901624000

The man page says PSXSEM type is a POSIX Semaphore. 手册页说PSXSEM类型是POSIX信号量。 Any clue what JDK uses POSIX Semaphores for? JDK使用POSIX信号量的任何线索? BTW, the app is a single threaded command line app at the moment. 顺便说一句,该应用程序目前是一个单线程命令行应用程序。

Potentially useful background: I first noticed this after upgrading to JDK 1.7 on Mac OS X 10.7.3: 潜在有用的背景:我在Mac OS X 10.7.3上升级到JDK 1.7后首先注意到这一点:

java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)

Update: repointing $JAVA_HOME at JDK 1.6 seems to be a workaround for the issue. 更新:在JDK 1.6上重新创建$JAVA_HOME似乎是该问题的解决方法。

java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-11M3635)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode)

What is JDK 1.7 doing differently? 什么是JDK 1.7做得与众不同?

I was able to trace it down to this block of code: 我能够将其追溯到这段代码:

BufferedImage image = null;
ImageInputStream stream = null;
try {
    stream = new FileImageInputStream(file);
    image = ImageIO.read(stream);

} catch (Exception ex) {
    log.error("Image could not be read: "+file.getPath());

} finally {
    // ImageIO closes input stream unless null is returned
    // http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#read(javax.imageio.stream.ImageInputStream)
    if (stream != null && image == null) {
        try {
            stream.close();
        } catch (IOException ex) {
            log.error("ERROR closing image input stream: "+ex.getMessage(), ex);
        }
    }
}

The JavaDocs specifically say that this method (unlike the others) closes the stream automatically. JavaDocs特别指出这种方法(与其他方法不同)会自动关闭流。 In fact, when you attempt to manually close it, it throws an exception saying 'closed'. 实际上,当您尝试手动关闭它时,它会抛出一个说“关闭”的异常。 I was using this overload since the other says it wraps it in a ImageInputStream anyway so I thought I'd save some work. 我正在使用这个重载,因为另一个说它无论如何都将它包装在ImageInputStream ,所以我想我会节省一些工作。

Changing the block to use a normal FileInputStream fixes the leak: 更改块以使用普通的FileInputStream修复了泄漏:

BufferedImage image = null;
InputStream stream = null;
try {
    stream = new FileInputStream(file);
    image = ImageIO.read(stream);

} catch (Exception ex) {
    log.error("Image could not be read: "+file);

} finally {
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException ex) {
            log.error("ERROR closing image input stream: "+ex.getMessage(), ex);
        }
    }
}

This appears to me to be a bug in JDK 1.7 as 1.6 worked fine here. 这在我看来是JDK 1.7中的一个错误,因为1.6在这里运行良好。

Update: I just submitted a bug report to Oracle for this issue. 更新:我刚刚 Oracle 提交了一个针对此问题的错误报告

I found another cause. 我找到了另一个原因。 It seems that the toRGB() method of ColorSpace is leaking semaphores. 似乎ColorSpace的toRGB()方法正在泄漏信号量。 Running the following code: 运行以下代码:

import java.awt.color.ColorSpace;
public class Test
{
    public static void main(String[] args) throws Throwable {
        final ColorSpace CIEXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
        for(int i = 0; i < 10000000; i++) {
            CIEXYZ.toRGB(new float[] {80f, 100, 100});
        }
    }
}

With: 附:

java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)

Will leave you out of system files. 会让你离开系统文件。

EDIT: already submitted a bug report to Oracle 编辑:已经向Oracle提交了错误报告

Update: As other users have said, ImageIO was leaking semaphores in 1.7.0_04 and 1.7.0_05. 更新:正如其他用户所说,ImageIO在1.7.0_04和1.7.0_05中泄漏了信号量。 The bug reports by user juancn and user mckamey have since been marked as fixed and closed (thanks guys!). 用户juancn和用户mckamey的错误报告已被标记为已修复并已关闭(感谢大家!)。 The explanation: 说明:

This fix reports a leak of file handlers on macosx. 此修复报告macosx上的文件处理程序泄漏。 It mentioned two ways to leak handlers: via ImageIO.read(ImageInputStream), and via semaphores. 它提到了两种泄漏处理程序的方法:通过ImageIO.read(ImageInputStream)和通过信号量。

I do not observe the first leak: we explicitly close input stream if we found an appropriate reader, and this is enough (at least on 1.7.4) to release file handles. 我没有观察到第一次泄漏:如果找到合适的阅读器,我们显式关闭输入流,这足以(至少在1.7.4上)释放文件句柄。

However, in case of semaphores we leak tons of handles: we perform color conversion for each line of jpeg image, and each time we create a semaphore (because we see 2 or more CPU installed on the system), then we reduce number of separate tasks down to 1 (because we have single scan line to process) and due to this never unlink the semaphore. 但是,在信号量的情况下,我们泄漏了大量的句柄:我们为jpeg图像的每一行执行颜色转换,每次我们创建一个信号量(因为我们看到系统上安装了2个或更多的CPU),那么我们减少了单独的数量任务减少到1(因为我们有单个扫描线来处理),因此从不取消链接信号量。

The same problem is present on Linux systems, but in less degree because we occupy single file handle per named semaphore, whereas on macosx we always occupy new file handle. 同样的问题出现在Linux系统上,但程度较低,因为我们占用每个命名信号量的单个文件句柄,而在macosx上我们总是占用新的文件句柄。

Suggested fix just postpones the creation of named semaphore until we clarify the number of separate tasks, so, now we do not create semaphores for image reading and simple color conversions (like ColorSpace.toRGB()). 建议的修复只是推迟命名信号量的创建,直到我们澄清单独任务的数量,因此,现在我们不创建用于图像读取和简单颜色转换的信号量(如ColorSpace.toRGB())。 Beside this, now we use pSem pointer as a trigger for the semaphore destruction. 除此之外,现在我们使用pSem指针作为信号量破坏的触发器。

Even though their reports indicate that the fix is in version 8, a backport report indicates that it was fixed in 1.7.0_06. 尽管他们的报告表明该修复程序是在版本8中,但是一个backport报告表明它已在1.7.0_06中修复。

So if you're seeing this on 1.7.0_04 or 05, updating to at least 1.7.0_06 will take care of this issue. 因此,如果您在1.7.0_04或05上看到此信息,则更新至至少1.7.0_06将解决此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM