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