简化为基本要素我有以下代码:
public class C_Test extends A_Test {
C_Test() {
super( null );
}
}
public abstract class A_Test {
private final String m_test;
public A_Test( String test ) {
m_test = C_ObjectUtil.defaultIfNull( test, "" );
if( m_test == null ) {
throw new RuntimeException( "it happened again!" );
}
}
}
public class C_ObjectUtil {
public static <T> T defaultIfNull( T object, T defaultObject ) {
return ( object == null ) ? defaultObject : object;
}
}
使用JDBC从DB2数据库中读取大约70 MB的数据后,调用new C_Test()
会抛出不可能的异常。到那时,构造函数被调用超过100000次。
将方法defaultIfNull
内联到构造函数A_Test
(这会删除泛型)后,一切正常运行!
环境:Sun JDK 1.7.0_25 64位,Linux
知道这里发生了什么吗?
这是堆栈跟踪。它与我上面显示的缩减版本不匹配。在构造函数m_test.equals( "null" )
中调用A_Test
时抛出此异常。
java.lang.NullPointerException
at com.src.db.attribvisitors.A_AttribVisitorAssignFromResultSet.<init>(A_AttribVisitorAssignFromResultSet.java:54)
at com.src.db.attribvisitors.C_AttribVisitorAssignFromSelectStatement.<init>(C_AttribVisitorAssignFromSelectStatement.java:37)
at com.src.db.attribvisitors.C_AttribVisitorAssignFromSelectStatement.<init>(C_AttribVisitorAssignFromSelectStatement.java:43)
at com.src.framework.db.migration.A_DbTableRow.initFromResultset(A_DbTableRow.java:96)
at com.src.framework.db.migration.helper.C_DbTableProcessor$1.process(C_DbTableProcessor.java:66)
at com.src.db.C_TxSql.query(C_TxSql.java:144)
at com.src.db.C_SqlExecuter$3.execute(C_SqlExecuter.java:142)
at com.src.db.C_SqlExecuter.execute(C_SqlExecuter.java:80)
at com.src.db.C_SqlExecuter.query(C_SqlExecuter.java:138)
at com.src.framework.db.migration.helper.C_DbTableProcessor.processTable(C_DbTableProcessor.java:58)
at com.src.framework.db.migration.helper.C_DbTableProcessor.processTable(C_DbTableProcessor.java:39)
at com.src.tools.C_DbExporter.exportTable(C_DbExporter.java:93)
at com.src.tools.C_DbExporter.exportTables(C_DbExporter.java:77)
at com.src.tools.C_DbExporter.exportTables(C_DbExporter.java:61)
at com.src.tools.C_DbExporterAndImporter.exportTables(C_DbExporterAndImporter.java:95)
at com.src.tools.C_DbExporterAndImporter.doMain(C_DbExporterAndImporter.java:83)
at com.src.common.C_MainUtil.runMain(C_MainUtil.java:150)
at com.src.tools.C_DbExporterAndImporter.main(C_DbExporterAndImporter.java:57)
答案 0 :(得分:3)
如果您没有向我们展示任何外部干预,这是不可能的。
此调用
m_test = C_ObjectUtil.defaultIfNull( test, "" );
将test
保存的值和引用的值推送到堆栈上的String
文字""
。调用该方法,消耗这两个引用。然后调用它
public static <T> T defaultIfNull( T object, T defaultObject ) {
return ( object == null ) ? defaultObject : object;
}
来自test
的值,即。 null
绑定object
,String
的引用值绑定到defaultObject
。执行条件运算符并返回defaultObject
,即。非空String
。这被分配给调用代码中的m_test
。没有什么可以拦截代码中的这些步骤。不是另一个线程,不是任何代理机制(它是直接调用的static
方法),而不是我能想到的任何东西。
您的错误在其他地方。
(如果您发布有助于确定真正问题的新细节,我将删除或编辑此答案。)
答案 1 :(得分:2)
你所描述的内容非常不可能。然而,这不是第一次不太可能发生。我有点犹豫要发布这个作为答案,因为它真的不是一个,但我们走了。
作为Kayaman points out,所描述的行为可能是由于JIT优化不正确。为了测试这个理论,我会执行两个步骤。
在发生不祥异常之前,打开-XX:+PrintCompilation
并监视输出以编辑相关方法。 这本身并不能证明JIT编译器正在应用不正确的优化。但是,它足以开始第二步,看看JIT正在生成什么机器代码。
打开-XX:+PrintAssembly
并浏览编译器输出的机器代码以获取相关方法。这是很多工作,特别是当你第一次这样做时。
我看到的方式有三种可能性。
最后要指出的一点是 - 克朗彻已经alluded - 是一种竞争条件的可能性。种族条件值得特别提及,因为它们落在第一类和第三类之间。它们可能与优化本身无关,但优化的加速可能会导致不必要的和无法实现的执行跟踪。
祝你好运,祝你好运。 :)
答案 2 :(得分:0)
我从 Sun JDK 1.7.0_25 64Bit 切换到 Sun JDK 1.7.0_55 64位,NPE消失了!