2015-09-05 43 views
0

我有一種情況,我使用C++代碼(Android - JNI/NDK)連接Java。
正如下面的代碼註釋中所解釋的,我試圖防止AssetManager實例被垃圾收集(因爲我在本機代碼中使用此實例)。在此代碼示例中,將由JVM垃圾收集AssetManager類成員嗎?

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 
public class AndroidLauncher extends AndroidApplication implements DroidBlaster { 
    // We need a reference to AssetManager (used by DroidBlaster JNI/NDK), 
    // in order to ensure that the AssetManager instance which is passed to 
    // native method DroidBlaster::create, is not garbage collected while 
    // the native object is in use. Furthermore we pass an instance of 
    // AndroidLauncher (this) to the Flm::initialize method, in order to 
    // ensure this class is not garbage collected. 
    private AssetManager assetManager; 

    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); 
     AssetManager assetManager = getAssets(); 
     initialize(new Flm(App.Type.PRO, this), config); 
    } 

    // ... 
    // .... 
} 

現在FLM類(其由在上面的代碼中的初始化方法中實例化的一個),包含其在構造intialized靜態DroidBlaster構件(其它接口由AndroidLauncher類實現)。

public class Flm extends Game { 
    static DroidBlaster droidblaster; 

    public Flm(App.Type aAppType, final DroidBlaster droidblaster) { 
     super(); 
     App.instance.setType(aAppType); 
     this.droidblaster = droidblaster; 
    } 

    // ... 
    // .... 
} 

我懷疑,這是正確執行,以確保,即FLM實例的存續期間,AndroidLauncher的AssetManager成員,將永遠不會被垃圾收集?

+0

您在onCreate中的本地'assetManager'變量隱藏了同名的成員字段 - 並且從不使用。這真的是你的代碼/你的意圖嗎? –

+0

是的,assetManager引用由本地代碼(C++)使用,它被傳遞給本地方法,而不是C++代碼中它存儲在類變量中。這一切都發生在'initialize'調用之前。爲了簡單起見,這裏沒有顯示代碼。所以我在C++代碼中使用AssetManager,但是我必須注意,我的引用沒有被JVM收集垃圾,因此我的問題的原因。 – Gio

回答

2

如果您想使用本機代碼中的對象,則需要本地或全局JNI引用。將對象傳遞給本地方法或使用JNI調用從字段中提取對象,將創建本地引用。當有問題的線程返回到VM時,這些過期並被丟棄。

如果您希望參考在跨本地代碼的調用中繼續有效,則需要使用NewGlobalRef創建全局參考。這些不會過期,並且在不再需要時必須明確刪除。

試圖用Java編寫的代碼來保存對象並不合乎情理。如果對象對於本機代碼還不可見,那麼它是否被收集並不重要 - 顯然沒有任何關於它的參考。如果該對象對本機代碼可見並且不能丟棄,那麼您應該從本機代碼創建一個全局引用。

有關更多信息,請參見JNI Tips