教你如何在軟件 測試 中搞定JNI的crash 今天可算是終于搞定困擾我一周的一個問題了。 我們的算法通過jni封裝,在 java 調用的時候總是隨機的crash掉,具體的位置在jvm里面,應該可以肯定是jvm做垃圾回收的時候死掉的。" name="description" />
MILY: Arial, Helvetica, sans-serif">教你如何在軟件測試中搞定JNI的crash
今天可算是終于搞定困擾我一周的一個問題了。
我們的算法通過jni封裝,在java調用的時候總是隨機的crash掉,具體的位置在jvm里面,應該可以肯定是jvm做垃圾回收的時候死掉的。但是并不知道是在回收哪塊內存出的問題,所以也就無從知道死的具體原因了。我們的程序是在jni層創建了一些java對象,然后返回給java層,大體結構像下面代碼一樣,我只能基本判斷是我們的jni層在創建對象的時候(也就是createInfo函數)出問題了,至于具體什么問題,我也不清楚。
public class Test {
public class Info {
public int x;
public int y;
public Info() {
x = 0;
y = 0;
}
}
public native Info createInfo();
// ...
}
因為我對java不是很熟悉,所以只好一邊學,一邊弄。最初就是在local/glbal reference這些概念上下功夫,來回的讀jni的specification,也沒有發現自己的問題。后期又學著使用一些java的調試工具,比如jhat啊,hpjmeter啊,但是仍然沒有什么頭緒。上周一周,就在這個問題上不斷的嘗試,也沒結果。
今天終于發現了問題所在,其實說來也很簡單。jni要創建的那些返回對象,是作為內部類定義的,所以在構造的時候需要傳一個外層類實例才能初始化。也就是說,雖然看上去Info類的構造函數是無參數的,但實際上它是有一個隱含參數的,相當于Info(Test outer)。如果在java層構造這個對象,那么outer參數會被自動傳入,但我們在jni層構造,就需要自己傳入這個參數了。如果沒有給出這個參數,jni編譯運行都沒有問題,但實際上,它是用了一個未知的對象(就是在棧里面的一個隨機值)來作為這個outer參數的,所以當這個對象需要釋放的時候(一般也就是在垃圾回收的時候)就會crash了。
現在想起來,其實這個問題我原來曾經有過一次小遭遇,那時我在使用有參數構造函數來創建一個內部嵌套類,發現構造出來的對象值是錯掉的。其實就是因為少傳了一個outer參數啊,但是當時我沒有去解決這個問題,而是繞過問題,采用構造函數無參數,然后在創建之后,再手工給每個數據字段賦值的方法。這樣雖然表面上也達到了目的,但是隱藏了問題。
事實一次次的告訴我們,遇到問題一定要解決。就算你暫時繞過這個問題,但早晚它還會出來的。
原文轉自:http://www.anti-gravitydesign.com