在这个代码示例中,AssetManager类成员会被JVM垃圾收集吗?

In this code example, will the AssetManager class member be garbage collected by the JVM?

本文关键字:JVM 成员 代码 AssetManager      更新时间:2023-10-16

我有一个情况,我的Java接口与c++代码(Android - JNI/NDK)。
正如在下面的代码注释中所解释的那样,我试图阻止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类(上面代码中由initialize方法实例化的那个)包含一个静态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成员,将永远不会被垃圾收集??

如果要使用本机代码中的对象,则需要对其进行本地或全局JNI引用。将对象传递给本机方法,或者使用JNI调用从字段中提取对象,都会创建一个本地引用。当有问题的线程返回VM时,这些线程将过期并被丢弃。

如果你想要一个引用在调用本机代码时仍然有效,你需要用NewGlobalRef创建一个全局引用。它们不会过期,当不再需要时必须显式删除。

试图用Java编写的代码来保存对象实际上是没有意义的。如果对象对本机代码还不可见,那么它是否被收集也无关紧要——显然没有任何东西保存对它的引用。如果对象对本机代码可见,并且不能被丢弃,那么您应该从本机代码创建一个全局引用。