java.util.zip.Inflater.init中的奇怪java.lang.OutOfMemoryError(本机方法)

时间:2012-11-26 05:44:13

标签: java runtime manifest out-of-memory

我需要在运行时从jar文件中读取Manifest文件。

代码:

JarFile someJar = new JarFile(jarFile);
manifest = someJar.getManifest();

但是,有时上面的代码会抛出OutOfMemoryError异常:

java.lang.OutOfMemoryError
    at java.util.zip.Inflater.init(Native Method)
    at java.util.zip.Inflater.<init>(Inflater.java:83)
    at java.util.zip.ZipFile.getInflater(ZipFile.java:278)
    at java.util.zip.ZipFile.getInputStream(ZipFile.java:224)
    at java.util.zip.ZipFile.getInputStream(ZipFile.java:192)
    at java.util.jar.JarFile.getBytes(JarFile.java:361)

有时可以告诉我如何避免这种异常(也许是另一种在运行时获取清单的方法)?

不过,我没有权限更改java堆大小。

3 个答案:

答案 0 :(得分:0)

这不是一个腐败的jar文件,让Inflater认为它需要分配大量的内存吗?

如果是,您可能会发现实际上可以捕获OutOfMemoryError。 (您通常不能或不应该捕获这些,但在尝试分配大量无法使用的内存的特定情况下,通常在实践中这样做是安全的。)

答案 1 :(得分:0)

这可能与您正在运行的ZIP文件无关。

查看JDK 1.7代码,Inflater构造函数最终调用名为init的本机方法,为其提供布尔参数。没有迹象表明任何对ZIP文件的引用。

似乎您正在使用的JRE中存在错误,或者您的系统在堆内存中非常有限(包含大多数ZIP功能的本机ZIP库非常小)。

您的JRE是否在OutOfMemoryError时发出堆转储?如果是这样,你可能想看看那里。

答案 2 :(得分:0)

这似乎是关于java.util.zip.Inflater的已知问题。

Inflater会在init期间分配堆内存,如果在路由后没有调用end(),则内存将一直存在,直到GC调用finalize函数。它堆很大,在使用所有内存之前不会调用finalize()。

请参阅此问题:excessive memory use by java
或者这个JDK错误报告:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4797189

我通过下面的代码验证它,直到JDK8,它仍然存在。

public static void main( String args[] ) throws InterruptedException {
    while ( true ) {
        //final Deflater deflater = new Deflater( 9, true );
        final Inflater inflater = new Inflater( true );
        // ....
        // if not call end() after using inflater, it will OOM
        // inflater.end();
        Thread.sleep(10);
    }
}

解决方案非常简单,只需在完成使用inflater后调用end()*