来自随机代码行的NullPointerExceptions

时间:2017-04-10 13:46:39

标签: java jvm osgi eclipse-rcp

我正在测试自定义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似乎无法正常工作)?

1 个答案:

答案 0 :(得分:3)

  

可能导致此行为的原因

以某种方式发送给流程的检测代理,硬件错误或SIGSEGV信号。

  

OpenJDK是否有类似IBMs -Xdump的选项,因此我可以获得核心转储   当有问题的NullPointerException发生时?

-XX:AbortVMOnException=java.lang.NullPointerException,但此选项仅适用于non-product版本。

  

在NullPointerException上设置gdb断点是否有一些技巧?

您可以尝试在以下功能中设置断点:

  • Runtime1::throw_null_pointer_exception(JavaThread*)
  • SharedRuntime::throw_NullPointerException(JavaThread*)
  • SharedRuntime::throw_NullPointerException_at_call(JavaThread*)

虽然可能会从更多不同的地方抛出异常。

更好的方法是设置将在每个抛出的异常上调用的JVM TI回调。以下是拦截异常的JVM TI代理an example

  

这可能与JVM隐式空值检查有关吗?有一些旗帜吗?   禁用它们

这可能是相关的。 -XX:-ImplicitNullChecks可能会禁用隐式空检查,但该标志仅在JVM的调试版本中可用。