当使用Lucene为文档建立索引时,我的JVM(1.6.0_29)在频繁使用时始终崩溃。我得到:
# # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00002b6b196d767c, pid=26417, tid=1183217984 # # JRE version: 6.0_29-b11 # Java VM: Java HotSpot(TM) 64-Bit Server VM (20.4-b02 mixed mode linux-amd64 compressed oops) # Problematic frame: # J org.apache.lucene.store.DataInput.readVInt()I # # If you would like to submit a bug report, please visit: # http://java.sun.com/webapps/bugreport/crash.jsp #
环境:
JDK:1.6u29(与1.6_02相同的问题)Lucene版本3.4.0
vm_info:适用于linux-amd64 JRE(1.6.0_29-b11)的Java HotSpot(TM)64位服务器VM(20.4-b02),由“ java_re”于gcc 3.2.2于2011年10月3日01:19:20构建( SuSE Linux)
操作系统:CentOS版本5.0(最终版)
jvm_args:-Dcatalina.home = / var / local / tomcat-8081 -Dcatalina.base = / var / local / tomcat-8081 -Djava.io.tmpdir = / var / tmp -Dfile.encoding = UTF-8 -Xmx1024M- XX:MaxPermSize = 96m
这似乎是jdk 1.7中已修复的jdk问题,但引入了其他问题。 https://issues.apache.org/jira/browse/LUCENE-3335 “ Java 7包含自1.6.0_21开始的readVInt问题修复程序(大约LUCENE-2975)”
那么,如何使用JDK 1.6解决此问题?我应该升级到jdk 1.7吗?
这些JDK问题也已在1.6.9_29(不仅是1.7.0u1)中修复。ReadVInt不再崩溃。因此,您的崩溃与任何“著名的java6 / 7错误”都没有关系(vint错误根本不会使JVM崩溃,它只是通过返回错误的值来破坏索引-并且该问题从Lucene 3.1开始就已得到修复)。
但是还有另一种可能使JVM崩溃的机会:您在64位平台(Linux)上,因此默认目录实现是MMapDirectory。Lucene使用黑客可以从虚拟地址空间取消映射文件的映射。JVM本身不允许这样做,但是使取消映射依赖于垃圾收集器,这对于Lucene来说是个问题。默认情况下,MMapDirectory在关闭IndexInputs后取消映射文件。MMapDirectory根本不同步,因此,当另一个线程在取消映射后尝试访问IndexInput时,它将访问未映射的地址,并将访问SIGSEGV。
如果您的代码正确,则不会发生这种情况,但是看起来您正在使用已关闭的IndexReader / IndexWriter访问索引。在Lucene 3.5(即将推出)之前,缺少IndexReader中的检查将可能使一个已经关闭的IndexReader及其所有关闭(且未映射)的IndexInputs尝试访问索引数据和段错误。
在3.5中,我们添加了其他安全检查来防止这种非法访问,但是不是100%(因为缺少同步)。我将检查代码,并检查没有任何东西可以访问封闭索引。
一个简单的检查(是否为您的问题)是使用NIOFSDirectory(在Linux上速度较慢)而不是MMapDirectory。如果它没有崩溃并且可能引发AlreadyClosedExceptions,则该错误正在访问已关闭的索引。