Simon在拙文《Android JNI開發(fā)入門之二》中提到了,Android JNI開發(fā)的深入學(xué)習(xí)的一些資料和方法,。最近Simon在學(xué)習(xí)《Java Native Interface: Programmer’s Guide and Specification》,,在學(xué)習(xí)過程中發(fā)現(xiàn)在JNI規(guī)范中關(guān)于引用部分是最難理解的,恕Simon愚鈍,,看了兩遍才對其思想略有理解,,在此和大家分享我對JNI規(guī)范中引用部分的理解,如果有錯誤之處,,希望能和各位網(wǎng)友一起探討,。
什么是JNI規(guī)范中對象引用在JNI編程中,Native代碼不能對Java虛擬機(jī)中對象的內(nèi)存分布有任何假設(shè),。因為Java虛擬機(jī)可以根據(jù)自己的策略定義自己對象的內(nèi)存布局,。這就要求JNI規(guī)范有如下要求:
JNI規(guī)范中的引用和Java中應(yīng)用有類比關(guān)系,,大家可以相互對照。 JNI引用的分類JNI規(guī)范中定義了三種引用——局部引用(Local reference),,全局引用(Global reference),,弱全局引用(Weak global reference)。 這算三種引用的生存期是不同的,,全局引用和弱全局引用的生存期為創(chuàng)建之后,,到程序員顯示的釋放他們。局部引用會被Java虛擬機(jī)在當(dāng)前上下文(可以理解成Java程序調(diào)用Native代碼的過程)結(jié)束之后自動釋放,。 全局引用和局部引用將會迫使Java虛擬機(jī)不會垃圾回收其指向的對象,。而弱全局引用指向的對象可以被Java虛擬機(jī)垃圾回收。 每種引用都有自己的用途,,比如當(dāng)Native函數(shù)返回的時候,,需要返回局部引用(和C語言的局部變量要區(qū)分開)。全局引用和弱全局引用在多線程之間共享其指向的對象等,。 局部引用這里重點(diǎn)要強(qiáng)調(diào)一下局部引用的有效期,,很多有C語言背景的程序員會認(rèn)為當(dāng)Native函數(shù)結(jié)束之后局部引用就無效了,和C語言的局部變量對應(yīng),。實(shí)際上JNI中的局部引用和C語言中局部變量是不同的,,他的有效期是當(dāng)前Native函數(shù)被調(diào)用的上下文中。我理解的調(diào)用上下文,,為Java虛擬機(jī)的調(diào)用流程,。Native函數(shù)是被Java虛擬機(jī)調(diào)用的,Native函數(shù)執(zhí)行完成之后,,控制流程將繼續(xù)返回給Java虛擬機(jī),。局部變量在Native函數(shù)中,由Native代碼調(diào)用Java虛擬機(jī)的JNI接口創(chuàng)建,,秉著誰創(chuàng)建誰銷毀的原則(軟件設(shè)計一個常用規(guī)則),,當(dāng)Native函數(shù)執(zhí)行完成之后,如果局部引用沒有被Native代碼顯示刪除,,那么局部引用在Java虛擬機(jī)中還是有效的,。Java虛擬機(jī)來決定在什么時候來刪除這個對象。這和C語言的局部變量概念是不同的,。這也可以解釋為什么Natvie函數(shù)能夠以一個局部引用為返回值了,。 JNI編程中,局部引用是最常被用到的概念。比如:大部分JNI函數(shù)都返回一個局部引用,,所以局部引用概念理解正確非常重要,。 局部引用在Native代碼顯示釋放非常重要。你可能會問,,既然Java虛擬機(jī)會自動釋放局部變量為什么還需要我在Native代碼中顯示釋放呢,?原因有以下幾點(diǎn):
在JNI中顯示釋放局部引用的函數(shù)為DeleteLocalRef,,大家可以查看手冊來了解調(diào)用方法,。 在JDK1.2中為了方便管理局部引用,引入了三個函數(shù)——EnsureLocalCapacity,、PushLocalFrame,、PopLocalFrame。這里介紹一下PushLocalFrame和PushLocalFrame函數(shù),。這兩個函數(shù)是成對使用的,,先調(diào)用PushLocalFrame,然后創(chuàng)建局部引用,,并對其進(jìn)行處理,,最后調(diào)用PushLocalFrame釋放局部引用,這時Java虛擬機(jī)也可以對其指向的對象進(jìn)行垃圾回收,??梢杂肅語言的棧來理解這對JNI API,調(diào)用PushLocalFrame之后Native代碼創(chuàng)建的所有局部引用全部入棧,,當(dāng)調(diào)用PopLocalFrame之后,,入棧的局部引用除了需要返回的局部引用(PushLocalFrame和PopLocalFrame這對函數(shù)可以返回一個局部引用給外部)之外,全部出棧,,Java虛擬機(jī)這時可以釋放他們指向的對象,。具體的用法可以參考手冊。這兩個函數(shù)使JNI的局部引用由于和C語言的局部變量用法類似,,所以強(qiáng)烈推薦使用,。 當(dāng)創(chuàng)建局部變量之后,將迫使Java虛擬機(jī)不對其指向的對象進(jìn)行垃圾回收,,直到Native代碼顯示調(diào)用了DeleteLocalRef刪除局部引用,。Native代碼調(diào)用DeleteLocalRef顯示刪除局部引用之后,Java虛擬機(jī)就可以對局部引用指向的對象垃圾回收了,。當(dāng)Native代碼創(chuàng)建了局部引用,,但未顯示調(diào)用DeleteLocalRef刪除局部引用,并返回Java虛擬機(jī)的話,,那么由虛擬機(jī)來決定什么時候刪除該局部引用,,然后對其指向的對象垃圾回收。程序員不能對java虛擬機(jī)刪除局部引用的時機(jī)進(jìn)行假設(shè),。 局部引用僅僅對于java虛擬機(jī)當(dāng)前調(diào)用上下文有效,,不能夠在多次調(diào)用上下文中共享局部引用。這句話也可以這樣理解:局部引用只對當(dāng)前線程有效,,多個線程之間不能共享局部引用,。局部引用不能用C語言的靜態(tài)變量或者全局變量來保存,否則第二次調(diào)用的時候,將會產(chǎn)生崩潰,。,。 本文敘述了JNI規(guī)范中局部引用的理解,后續(xù)文章《Android JNI編程提高篇之二》我們將會繼續(xù)關(guān)注全局變量和弱全局變量,。 |
|