我正在测试自定义Eclipse-RCP应用程序。这个应用程序做了一些简单的初始化,然后启动了一堆线程,这些线程解析了工作区内的很多XML文件。来自随机代码行的NullPointerExceptions
在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仅仅是一个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
似乎没有工作)?
279:final long tid = getThreadId(Thread.currentThread());可以为null。如果getThreadId()返回一个Long,则返回的值可以为null,并且在尝试解析为一个原始long时会导致NPE。 – Wietlol
[getThreadId](http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/80280d8b40e9/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java#l1492)返回'long '。 –
这可能是因为你的堆栈跟踪以某种方式被破坏,所以你看到的跟踪实际上与产生异常的地方没有任何关系。 –