【发布时间】:2017-09-05 14:28:49
【问题描述】:
我正在测试一个自定义的 Eclipse-RCP 应用程序。这个应用程序做了一些简单的初始化,然后启动了一堆线程来解析工作空间内的大量 XML 文件。
大约在 1000 次执行中,其中一个线程因 NullPointerException 而崩溃。这通常发生在 Xerces 中,有时在其他库中,有时在 Java 标准库中。问题是那些 NullPointerExceptions 似乎发生在没有取消引用指针的行中。例如:
java.lang.NullPointerException
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync$HoldCounter.<init>(ReentrantReadWriteLock.java:279)
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter.initialValue(ReentrantReadWriteLock.java:289)
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter.initialValue(ReentrantReadWriteLock.java:286)
at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:180)
at java.lang.ThreadLocal.get(ThreadLocal.java:170)
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryAcquireShared(ReentrantReadWriteLock.java:481)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireShared(AbstractQueuedSynchronizer.java:1282)
at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.lock(ReentrantReadWriteLock.java:727)
at org.eclipse.osgi.container.ModuleDatabase.readLock(ModuleDatabase.java:744)
at org.eclipse.osgi.container.ModuleDatabase.getWiring(ModuleDatabase.java:431)
at org.eclipse.osgi.container.ModuleContainer.getWiring(ModuleContainer.java:398)
at org.eclipse.osgi.container.ModuleRevision.getWiring(ModuleRevision.java:137)
at org.eclipse.osgi.container.ModuleWire.getProviderWiring(ModuleWire.java:51)
at org.eclipse.osgi.internal.loader.BundleLoader.findRequiredSource(BundleLoader.java:1114)
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:392)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:352)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:344)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.eclipse.core.internal.resources.ProjectContentTypes.usesContentTypePreferences(ProjectContentTypes.java:116)
at org.eclipse.core.internal.resources.ContentDescriptionManager.getDescriptionFor(ContentDescriptionManager.java:321)
at org.eclipse.core.internal.resources.File.getContentDescription(File.java:255)
at my_app.ModelParser.getContentType(ModelParser.java:54)
at my_app.ModelParser.parse(ModelParser.java:43)
at my_app.ValidationModelsCache.getModel(ValidationModelsCache.java:44)
at my_app.BuilderContext.getParseResult(BuilderContext.java:37)
at my_app.ValidationHandler.validate(ValidationHandler.java:37)
at my_app.ProjectValidationBuilder$1.run(ProjectValidationBuilder.java:57)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
第279行没有null。其实整个方法没有一个解引用:
276: static final class HoldCounter {
277: int count = 0;
278: // Use id, not reference, to avoid garbage retention
279: final long tid = getThreadId(Thread.currentThread());
280: }
我已经两次和三次检查我有正确的来源。我什至反汇编了其中的一些方法,似乎没有任何方法可以取消对 null 的引用。
这是另一个例子:
Caused by: java.lang.NullPointerException
at com.google.common.collect.ObjectArrays.checkElementsNotNull(ObjectArrays.java:233)
at com.google.common.collect.ObjectArrays.checkElementsNotNull(ObjectArrays.java:226)
at com.google.common.collect.ImmutableList.construct(ImmutableList.java:303)
at com.google.common.collect.ImmutableList.of(ImmutableList.java:98)
at com.google.common.collect.Iterables.concat(Iterables.java:432)
第 233 行只是一个返回语句:
229: static Object[] checkElementsNotNull(Object[] array, int length) {
230: for (int i = 0; i < length; i++) {
231: checkElementNotNull(array[i], i);
232: }
233: return array;
234: }
到目前为止,这似乎只发生在一台机器上:
CPU: Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
Linux: 4.9.0-2-amd64 #1 SMP Debian 4.9.18-1 (2017-03-30) x86_64 GNU/Linux
Java:
openjdk version "1.8.0_121"
OpenJDK Runtime Environment (build 1.8.0_121-8u121-b13-4-b13)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode
但在几个不同的 Java 和内核版本上重现。
什么可能导致这种行为,如何调试它?
OpenJDK 是否有类似IBMs -Xdump 的选项,以便在发生有问题的 NullPointerException 时获取核心转储?
在 NullPointerException 上设置 gdb 断点有什么技巧吗?我猜 jdb 赶不上它。
这可能与 JVM 隐式空检查有关吗?是否有一些标志可以禁用它们(-Xrs 似乎不起作用)?
【问题讨论】:
-
279: 最终长 tid = getThreadId(Thread.currentThread());可以为空。如果 getThreadId() 返回 Long,则返回值可以为 null,并且在尝试解析为原始 long 时会导致 NPE。
-
getThreadId 返回
long。 -
这可能是因为您的堆栈跟踪不知何故被破坏了,所以您看到的跟踪实际上与产生异常的地方没有任何关系。
标签: java jvm osgi eclipse-rcp