You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端OpenCV内存泄漏:垃圾回收无法回收Mat对象问题

OpenCV Mat对象帧处理场景内存泄漏问题解析

问题现象

开发逐帧处理视频的演示应用时,发现函数内部创建的Mat对象在函数执行结束后无法被正常回收,导致内存持续上涨:

class MainActivity ...
    ...

    override fun onCameraFrame(inputFrame: CvCameraViewFrame): Mat {
        val rgbaMat: Mat = inputFrame.rgba()!!
        val lets_have_a_memory_leak = false
        if (lets_have_a_memory_leak) {
            val unused_leaker = Mat.zeros(rgbaMat.size(), rgbaMat.type())
        }
        return rgbaMat
    }
  • 开关lets_have_a_memory_leak == false时,内存占用稳定无异常:
    内存占用平稳截图
  • 开关lets_have_a_memory_leak == true时,内存快速持续消耗,直到应用被系统杀死:
    内存持续泄漏截图

目前已验证的现象:

  • 将方法内临时使用的Mat预分配为类成员变量复用时,可暂时规避泄漏
  • 主动对临时Mat调用unused_leaker.release(),可完全阻止内存溢出

核心原理

GC没有按预期回收内存不是GC故障,本质是OpenCV Java/Kotlin绑定的内存模型和JVM GC管辖范围不匹配:

  • JVM GC的回收范围仅限JVM堆内存,也就是Mat这个Kotlin/Java对象本身占用的内存,这部分只有几十字节,占比极低
  • Mat存储像素数据的实际内存是直接在Native堆分配的,完全不在JVM GC的检测、回收范围内
  • OpenCV的绑定逻辑确实给Mat写了finalize兜底释放逻辑:只有当JVM堆内存不足、触发GC回收Mat的Java对象时,才会顺带调用native方法释放对应的Native内存。但逐帧处理场景下,每秒会创建数十个临时Mat,每个Mat对应的Java对象占用内存极小,JVM堆内存长期处于充足状态,GC几乎不会被触发,Native堆的像素内存就会无限制累积,最终触发OOM。

最佳实践

  • 所有临时创建的Mat对象,使用完毕后必须主动调用.release()手动释放Native内存,绝对不要依赖finalize机制兜底——finalize执行时机完全不可控,且在高版本Android/JDK中已被废弃。
  • 高频帧处理场景下,优先复用预分配的类成员Mat对象,减少重复分配、释放的性能开销。
  • 可通过Kotlin扩展函数实现use作用域,自动完成释放,避免遗漏:
inline fun <T> Mat.use(block: (Mat) -> T): T {
    return try {
        block(this)
    } finally {
        release()
    }
}

// 调用示例
Mat.zeros(rgbaMat.size(), rgbaMat.type()).use { tempMat ->
    // 在此处对tempMat做处理
} // 作用域结束自动调用release,即使抛出异常也不会泄漏

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 15:48:22