JVM在Lucene DataInput.readVInt上崩溃

在使用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),构建于2011年10月3日01:19:20,“java_re”与gcc 3.2.2( 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参数=96米

它似乎是一个jdk问题,已在jdk 1.7中修复,但其他问题已经引入。 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使用hack能够从虚拟地址空间取消映射映射文件。 JVM本身不允许这样做,但是取消依赖垃圾收集器,这对Lucene来说是一个问题。 默认情况下,MMapDirectory在关闭IndexInputs后取消映射文件。 MMapDirectory根本没有同步,因此当另一个线程在取消映射后尝试访问IndexInput时,它将访问未映射的地址并将SIGSEGV。

如果您的代码是正确的,这不会发生,但看起来您正在使用已经关闭的IndexReader / IndexWriter来访问索引。 在Lucene 3.5(即将推出)之前,在IndexReader中缺少检查将使已经关闭的IndexReader及其所有已关闭(和未映射)的IndexInputs尝试访问索引数据和段错误成为可能。

在3.5中,我们添加了额外的安全检查以防止此非法访问,但它不是100%(因为缺少同步)。 我会检查代码并检查没有访问封闭索引。

检查这是否是您的问题的简单检查将是使用NIOFSDirectory(在Linux上较慢)而不是MMapDirectory。 如果它没有崩溃并且可能抛出AlreadyClosedExceptions,则该错误正在访问已关闭的索引。

根据这篇文章 ,以下内容可能会在Java 6中引起它:

请注意:如果Java 6用户使用其中一个默认情况下未启用的JVM选项,则会受到影响:-XX:+ OptimizeStringConcat或-XX:+ AggressiveOpts

你在用它们吗?