【问题标题】:My Android app suddenly closes我的 Android 应用突然关闭
【发布时间】:2014-10-06 10:41:16
【问题描述】:

我正在使用 OpenCV 开发增强现实 Android 应用。

现在,当我运行我的应用程序时,它会运行几秒钟,然后突然关闭,没有警告,也没有 logcat 中的错误消息。我认为这与 RAM 内存耗尽有关,但我很难弄清楚是什么原因造成的。此外,当我在我的应用程序突然关闭时检查 ddms 时,所有进程(不仅是我的应用程序)开始消失。有时我会在 logcat 中收到这样的错误消息:

cannot map BpMemoryHeap (binder=0x767e84c0), size=2883584, fd=53 (Out of memory)

这就是我的 OnPreviewFrame 的设置方式:

  1. 添加一些回调缓冲区:

    float bytesPerPix = ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8.0f;
    int frame_byteSize = (int) ((size.width * size.height) * bytesPerPix);
    
    for(int i = 0; i< AppConfig.AMOUNT_PREVIEW_BUFFERS ; i++) {
        camera.addCallbackBuffer(new byte[frame_byteSize]);
    }
    
  2. 在相机上设置 PreviewCallback:

    cameraRenderer.getCamera().setPreviewCallbackWithBuffer(virtualLayerRenderer);
    

这是我在 OnPreviewFrame 方法中调用的 updateCameraPose 函数:

public void updateCameraPose(byte[] frameData, Camera camera) {

    Size size = camera.getParameters().getPreviewSize();

    Mat frameImg = new Mat();
    Mat mYuv = new Mat( size.height + size.height/2, size.width, CvType.CV_8UC1 );
    mYuv.put( 0, 0, frameData );

    camera.addCallbackBuffer(frameData);

    Imgproc.cvtColor( mYuv, frameImg, Imgproc.COLOR_YUV2GRAY_NV21, 1);

    FindCameraPose task = new FindCameraPose();
    task.execute(frameImg, cameraPose);

}

这个函数调用一个asynctask并执行它,这是我的asynctask的代码:

private class FindCameraPose extends AsyncTask<Mat, Void, Mat> {

    @Override
    protected Mat doInBackground(Mat... params) {
        String t = cameraIntDistPath;
        getCameraPose( 
                params[0].getNativeObjAddr(), 
                t, 
                params[1].getNativeObjAddr());
        return params[1];
    }

    @Override
    protected void onPostExecute(Mat result) {
        super.onPostExecute(result);
        if(result != null && !result.empty())
            Log.d(TAG, "Camera Pose: "+result.dump());
    }
    private native boolean getCameraPose(long frameImagePtr, String cameraIntDistPath, long cameraPosePtr);

}

asynctask 然后调用获取相机位姿的本机方法,这是本机方法的代码:

JNIEXPORT jboolean JNICALL Java_be_wouterfranken_arboardgame_rendering_tracking_CameraPose_00024FindCameraPose_getCameraPose
      (JNIEnv * env, jobject jobject, jlong frameImagePtr, jstring cameraIntDistPath, jlong cameraPosePtr)
{
    Mat *camPose = (Mat *) cameraPosePtr;
    Mat *frameImage = (Mat *) frameImagePtr;

    __android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Mats setup ...");

    const char * path = env->GetStringUTFChars(cameraIntDistPath, NULL);

    __android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Path string setup started ... %s",path);

    Mat intrinsics;
    Mat distortion;

    __android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Search for cameraPose started...");

    Utilities::loadCameraCalibration(path, intrinsics, distortion);
    env->ReleaseStringUTFChars(cameraIntDistPath, path);

    __android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Camera calibration done");

    bool patternFound = pd.findPattern(*frameImage, pti);

    __android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Patterns found? %d",patternFound);

    if(patternFound) {
        pti.computePose(p, intrinsics, distortion);
        *camPose = pti.pose3d;
        __android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Pose computed");
    }

    return patternFound;
}

有什么想法吗?

更新

好的,所以我将内存泄漏缩小到本机堆中的泄漏,它来自 opencv_java 库。特别是当我关闭检测关键点的调用时,泄漏似乎消失了。我希望这不是 OpenCV 中的错误,但现在看起来是这样。另外,即使我尝试使用另一个检测器(SIFT/SURF/ORB/BRISK),这也没关系,仍然是内存泄漏。

有人知道这可能与什么有关吗?

【问题讨论】:

  • 考虑使用 OpenCV native 相机,在您的场景中它可能比 Java 相机更有效。
  • 是的,我知道这可能会更好。问题是我还使用 Google 的 Cardboard VR SDK,我认为如果我使用 OpenCV 原生相机,使用它会成为问题(因为两个 API 都需要自己的视图)。

标签: android opencv android-asynctask java-native-interface android-camera


【解决方案1】:

您是否尝试将 "android:largeHeap="true" 参数放在 AndroidManifest.xml 中的 Application 标记中?

类似这样的:

<application android:label="@string/app_name" android:largeHeap="true">

<activity android:name=".MainActivity" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

【讨论】:

  • 很遗憾,这没有帮助。
  • 那么也许你必须减少图像缓冲区的大小。更改分辨率或将颜色类型更改为带有 les deph 的内容。抱歉,我无法为您提供更多帮助。
  • 我无法想象这会有所帮助,因为我刚刚设法看到我的堆大小,当我的应用程序崩溃时它大约为 1GB。所以这肯定指向我的 C++ 代码中的内存泄漏。
【解决方案2】:

好的,所以我只是回答了我自己的问题。

我在计算完成之前将回调缓冲区返回给相机,并且在每一帧上都这样做。这使相机可以在几乎每一帧(当然很多)上运行 getCameraPose 方法。这几乎在每一帧都调用了跟踪代码,因此添加的工作量超出了解决的范围,这解释了堆中使用的大量内存。

从现在开始,我将确保仅在完全处理完帧后将缓冲区返回给相机。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    相关资源
    最近更新 更多