2

我需要在运行时从 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 堆大小。

4

3 回答 3

0

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

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

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

您的 JRE 是否在OutOfMemoryError? 如果是这样,你可能想看看那里。

于 2012-11-26T06:15:21.123 回答
0

是不是一个损坏的 jar 文件让 Inflater 误以为它需要分配大量内存?

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

于 2012-11-26T05:57:44.393 回答
0

这似乎是一个关于java.util.zip.Inflater.

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

请参考这个问题: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);
    }
}

解决方法很简单,end()*用完inflater后调用。

于 2016-07-18T10:58:06.660 回答