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