【问题标题】:Android NDK releasing memoryAndroid NDK 释放内存
【发布时间】:2014-06-13 03:29:09
【问题描述】:

我有基本的 ndk 项目: NdkTest.java 类和ndk.cpp 文件。现在我有应该创建一次的 C++ 对象,并在应用程序被杀死或关闭时销毁。 所以我的NdkTest.java 看起来像这样:

NdkTest {
    static {
        System.loadLibrary("testLib");
    }
    public static native method1();
    public static native method2();
}

ndk.cpp 看起来像这样:

#include <jni.h>

extern "C" {
    void packageName_ClassName_method1(Env *, class);
    void packageName_ClassName_method2(Env *, class);
}

ManagerClass *manager = NULL; //this is actually in .h file but for simplicity of this example I put it here

void packageName_ClassName_method1(Env *env, class clazz) {
    if(manager==NULL) {
        manager = new Manager();
    }
    manager->method1();
}

void packageName_ClassName_method2(Env *env, class clazz) {
    if(manager==NULL) {
        manager = new Manager();
    }        
    manager->method2();
}

现在... manager 应该只创建一次,它应该被我所有​​的本地方法使用。此代码将编译并工作,但它会导致内存泄漏,因为管理器永远不会被破坏。应该在哪里销毁? 当然,我可以创建像 createManager()destroyManager() 这样的 java 方法,但我不想这样做。甚至可能吗? 我尝试像这样使 Manager 对象成为全局对象:

ManagerClass manager;

void packageName_ClassName_method1(Env *env, class clazz) {    
    manager.method1();
}

void packageName_ClassName_method2(Env *env, class clazz) {    
    manager.method2();
}

它也可以工作,但我不知道它的析构函数是否被调用过。我在那里输入了登录信息,但它从未显示过。

所以我的问题是:在 Android 原生开发中处理释放内存的最佳方法是什么?有什么好的模式吗?如果唯一的方法是创建 java 方法createManager()destroyManager() 那么我应该在哪里调用destroyManager()? Java finalize() 不能保证被调用,我应该把它放在哪里?


我找到了关于这个主题的精彩视频:

大约 31 分钟。是最好的部分:)

【问题讨论】:

    标签: java android c++ memory android-ndk


    【解决方案1】:

    对于内存管理的 Android 模型,不能保证会调用任何析构函数。本书唯一的保证是onPause() 方法将被调用用于前台活动。

    OTOH,Linux 内核负责释放已被正常关闭或强制关闭的进程使用的所有资源。

    因此,除非您的 Singleton 锁定了一些无法被内核自动回收的非常特殊的系统资源,否则您不必担心它是析构函数。但如果确实如此(例如,它锁定了相机),你需要一个防弹机制来尽早解锁这个资源,最好是在onPause()

    所有这些讨论都不适用于单例的创建。您可以使用上述任何一种方法,并选择最适合您的架构的方法。仅记住在创建 Manager 对象时可能会开始应用程序销毁序列的竞争情况(仅可能在多线程场景中)。

    【讨论】:

    • 所以你是说我可以用new 创建它而没有delete 离开,系统会关心释放内存吗?我的班级不使用任何与 Android 相关的东西。出于效率原因,这只是我用 C++ 编写的一些算法。
    • 是的,你可以忽略删除部分,但是要记住两个场景:确保你不再重新创建管理器(例如你的应用程序被关闭并再次打开,但系统决定进程可以重用),如果你使用工具寻找内存泄漏,他们会抱怨。他们不关心Android进程管理的极端情况,所以他们会满足于最天真的delete
    • 多么奇怪的评论。在 C++ 中,您不能关心您分配的内存。当您不再需要它时,您必须将其丢弃。所以说 te OP 不应该关心这些事情是错误的。当然,在“应用程序被杀死”的情况下,这并不重要。但是你仍然应该关心资源分配/释放。你不能说:'是的,我们的库应该被操作系统杀死'或类似的东西。
    • @WernerVanBelle 对不起。现实有时对纯粹主义者来说是痛苦的。您可能会声称一般的全局变量,尤其是单例模式是不好的做法,但是语言确实允许这些,并且运行时环境会负责销毁这些。在 Android 上,在JNI_OnLoad() 上创建的对象实际上等同于全局变量,因为我们可能永远没有机会控制它们的销毁。这同样适用于 Java finalize() 方法:您不应依赖所有被调用的 finalize() 方法,或以特定顺序调用。
    • @AlexCohn 当然,这可能是它在 Java 中的方式。这并没有改变这样一个事实,即如果您编写 C++,则必须注意您的内存。让操作系统清理你的烂摊子是没有选择的。另外,你至少可以在Java代码的finalize方法中清理C++资源,否则会导致内存泄漏。
    猜你喜欢
    • 2011-04-02
    • 2020-05-21
    • 2012-02-25
    • 2019-01-20
    • 2019-01-08
    • 2011-12-08
    • 2013-07-26
    • 1970-01-01
    • 2011-05-10
    相关资源
    最近更新 更多