来自随机代码行的 NullPointerExceptions
NullPointerExceptions from random lines of code
我正在测试自定义 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.run(ProjectValidationBuilder.java:57)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
Nothing can be null
in the line 279. 事实上,整个方法中没有一个解引用:
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 行只是一个 return 语句:
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
似乎不起作用)?
What could be causing this behavior
检测代理、硬件错误或 SIGSEGV 信号以某种方式发送到进程。
Does OpenJDK has option like IBMs -Xdump so I can obtain core dump
when problematic NullPointerException happens?
-XX:AbortVMOnException=java.lang.NullPointerException
,但此选项仅在 构建中可用。
Is there some trick to set gdb breakpoint on NullPointerException?
您可以尝试在以下函数设置断点:
Runtime1::throw_null_pointer_exception(JavaThread*)
SharedRuntime::throw_NullPointerException(JavaThread*)
SharedRuntime::throw_NullPointerException_at_call(JavaThread*)
尽管可能会从更多不同的地方抛出异常。
更好的方法是设置 JVM TI 回调,每次抛出异常时都会调用该回调。这里是an example拦截异常的JVM TI agent
Could this be related to JVMs implicit null checks? Is there some flag
to disable them
这可能是相关的。 -XX:-ImplicitNullChecks
可能会禁用隐式 null 检查,但该标志再次仅在 JVM 的调试版本中可用。
我正在测试自定义 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.run(ProjectValidationBuilder.java:57)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
Nothing can be null
in the line 279. 事实上,整个方法中没有一个解引用:
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 行只是一个 return 语句:
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
似乎不起作用)?
What could be causing this behavior
检测代理、硬件错误或 SIGSEGV 信号以某种方式发送到进程。
Does OpenJDK has option like IBMs -Xdump so I can obtain core dump when problematic NullPointerException happens?
-XX:AbortVMOnException=java.lang.NullPointerException
,但此选项仅在
Is there some trick to set gdb breakpoint on NullPointerException?
您可以尝试在以下函数设置断点:
Runtime1::throw_null_pointer_exception(JavaThread*)
SharedRuntime::throw_NullPointerException(JavaThread*)
SharedRuntime::throw_NullPointerException_at_call(JavaThread*)
尽管可能会从更多不同的地方抛出异常。
更好的方法是设置 JVM TI 回调,每次抛出异常时都会调用该回调。这里是an example拦截异常的JVM TI agent
Could this be related to JVMs implicit null checks? Is there some flag to disable them
这可能是相关的。 -XX:-ImplicitNullChecks
可能会禁用隐式 null 检查,但该标志再次仅在 JVM 的调试版本中可用。