【问题标题】:SIGSEGV on Android + OpenCVAndroid + OpenCV 上的 SIGSEGV
【发布时间】:2016-06-23 23:47:39
【问题描述】:

我遇到了奇怪的问题。简而言之:我编写了一个使用 OpenCV 和两个活动的 Android 应用程序:

Activity1预览前置摄像头并在用户点击时启动Activity2,通过Intent发送当前帧的地址

Activity2 将给定地址下帧的Mat clone 类型的本地字段分配给它,并允许用户对其进行简单操作(即在HSV 颜色空间中执行inRange 方法)。 Mat 被转换为位图并显示在 ImageView 中:这发生在 Activity2 开始(对于原始捕获的帧)和每次用户操作 SeekBar 之后。

Activity1 是 Activity2 的父级,因此单击后退按钮会重新启动 Activity1。 现在是奇怪的部分

1) 一段时间后(不到 1 分钟)Activity1 崩溃,libc: Fatal signal 11 (SIGSEGV)- 你可以想象,当 Activity2 从未启动时它不会发生

2) 如果我通过简单地返回到 Activity1 并再次单击来重新启动 Activity2,则会调用常规生命周期中的 OnCreate() 和其他方法,并且当执行从 Mat 到 Bitmap 的转换时,应用程序会崩溃并出现相同的致命信号错误:

Utils.matToBitmap(mCapturedFrame, bm);

所以,这是 OpenCV 的函数在重新启动 Activity 后第一次被调用。最好的部分是,mCapturedFrame 存在并且上述方法在加载 OpenCV 库后调用。更重要的是,我 release() 本地创建的 Mats,以及包含捕获帧 Mat 的字段(当我从 Activity2 返回时)。该错误看起来像是 Activity1 的内存泄漏,但在哪里?!

我真的看不出我在这里做错了什么,并且很高兴有任何建议。随意从这里下载我的 java 代码文件:http://speedy.sh/RMPKH/thesis.zip

【问题讨论】:

    标签: android opencv bitmap segmentation-fault


    【解决方案1】:

    如果我理解正确,您将 Mat 的本机对象地址从 Activity 1 发送到 Activity 2。然后,在 Activity 2 中,您正在执行以下操作:

    Mat receivingMat = new Mat(nativeAddrFromActivity1);
    

    在这种情况下,问题在于您遇到了双重释放错误。这样做的原因很重要,但我会引导你完成。首先让我们看一下该构造函数的 OpenCV Mat 实现:

    public Mat(long addr)
    {
        if (addr == 0)
            throw new java.lang.UnsupportedOperationException("Native object address is NULL");
        nativeObj = addr;
    }
    

    当然,receiveingMat 将在未来某个时候超出范围,然后被 GarbageCollector 收集。在这种情况下,将调用 finalize 方法。这导致调用 OpenCV 的 Mat 实现的原生删除函数,因为 finalize 方法实现如下:

    @Override
    protected void finalize() throws Throwable {
        n_delete(nativeObj);
        super.finalize();
    }
    

    n_delete函数定义如下(see here):

    //
    //  native support for java finalize()
    //  static void Mat::n_delete( __int64 self )
    //
    
    JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
      (JNIEnv*, jclass, jlong self);
    
    JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
      (JNIEnv*, jclass, jlong self)
    {
        delete (Mat*) self;
    }
    

    在我看来,这是 OpenCV for Android 中的一个错误。使用本机地址构造函数创建的 Mat 不应调用 n_delete 函数,因为它没有本机 Mat 标头的所有权,也不负责清理它。我想不出你会喜欢这种行为的任何情况......


    要解决您的问题,您应该将 Mat 转换为位图,将其保存到临时文件中,然后通过 Intent Extras 将该文件的路径从 Activity 1 发送到 Activity 2。

    【讨论】:

    • 感谢您的回答。抱歉这么晚才回信。不幸的是,我无法检查解决方案是否有效,但您分析它的方式似乎很好。我通过禁用后退按钮功能解决了这个问题(我只是从活动 XML 配置中删除了“父活动”属性)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多