有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java JDK 1.7:POSIX信号导致“打开的文件太多”?

我已经看过了其他类似的问题,但它们似乎是由其他问题引起的

首先,我确保明智地关闭了所有文件句柄,然后使用^{}查看我的文件列表

它在我的整个运行时保持不变,但随后我会定期在lsof中列出大约10000个条目,如下所示:

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

手册页说PSXSEM类型是POSIX信号量。知道JDK使用POSIX信号量做什么吗?顺便说一句,该应用程序目前是一个单线程命令行应用程序

潜在有用的背景:在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)

更新:在JDK1.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)

JDK1.7有什么不同之处


共 (3) 个答案

  1. # 1 楼答案

    更新:正如其他用户所说,ImageIO在1.7.0_04和1.7.0_05中泄漏了信号量。用户juancn和用户mckamey的错误报告已被标记为已修复和已关闭(谢谢大家!)。解释如下:

    This fix reports a leak of file handlers on macosx. It mentioned two ways to leak handlers: via ImageIO.read(ImageInputStream), and via semaphores.

    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.

    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.

    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.

    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()). Beside this, now we use pSem pointer as a trigger for the semaphore destruction.

    尽管他们的报告表明修复程序是在版本8中,但后端口报告表明它是fixed in 1.7.0_06.

    因此,如果您在1.7.0_04或05上看到此问题,更新到至少1.7.0_06将解决此问题

  2. # 2 楼答案

    我可以追溯到这段代码:

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

    JavaDocs特别指出,这种方法(与其他方法不同)会自动关闭流。事实上,当您尝试手动关闭它时,它会抛出一个异常,显示“closed”。我在使用这个重载,因为另一个说它用ImageInputStream包装,所以我想我应该节省一些工作

    将块更改为使用普通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);
            }
        }
    }
    

    在我看来,这似乎是JDK1.7中的一个bug,因为1.6在这里工作得很好

    更新:我只是submitted a bug report向Oracle咨询这个问题

  3. # 3 楼答案

    我找到了另一个原因。ColorSpace的toRGB()方法似乎正在泄漏信号量。运行以下代码:

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

    与:

    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)
    

    会将您从系统文件中删除

    编辑:已向Oracle提交了一份bug report