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

MLKit姿态检测APP内存溢出崩溃问题求助(Kotlin)

Kotlin下MLKit姿态估计APP内存崩溃解决方案

核心问题分析

原代码存在多处内存浪费与资源未合理释放的问题:

  • 重复创建Bitmap:从TextureView获取bm后,额外通过压缩再解码生成新Bitmap,无端占用内存
  • 字符串拼接低效:循环中用+=拼接字符串,会生成大量临时String对象
  • 未及时回收Bitmap资源:使用后的Bitmap未主动释放,导致内存堆积
  • 帧处理无节流:短时间内处理过多帧,引发内存缓冲区耗尽

具体修复方案

  • 避免重复创建Bitmap:直接用TextureView获取的Bitmap创建InputImage,跳过冗余的压缩解码流程
  • 优化字符串拼接:改用StringBuilder减少临时对象生成
  • 主动回收Bitmap:在确认不再使用Bitmap时调用recycle()释放内存
  • 添加帧节流:控制处理帧率,避免短时间内任务堆积
  • 优化视图资源:移除视图时确保相关资源被释放,避免内存泄漏

修改后的代码

// 新增帧节流控制,限制每秒处理5帧
private var lastProcessTime = 0L
private val processInterval = 200L // 200ms间隔

Log.d("LOG:", "Here")

val bm = mTextureView.bitmap
val currentTime = System.currentTimeMillis()

if (bm != null && currentTime - lastProcessTime > processInterval) {
    lastProcessTime = currentTime
    Log.d("LOG:", "not null")

    // 直接用原Bitmap创建InputImage,省去重复解码步骤
    val inputImage = InputImage.fromBitmap(bm, 0)
    poseDetector.process(inputImage)
        .addOnSuccessListener { pose ->
            if (parentLayout.childCount > 4) {
                val removedView = parentLayout.getChildAt(4)
                parentLayout.removeView(removedView)
                // 如果Draw类持有自定义资源,可在此调用回收方法,比如removedView.release()
            }
            imgView.setImageBitmap(bm)
            if (pose.allPoseLandmarks.isNotEmpty()) {
                val draw = Draw(applicationContext, pose)
                parentLayout.addView(draw)
                
                // 用StringBuilder优化字符串拼接,减少内存开销
                val contentBuilder = StringBuilder()
                pose.allPoseLandmarks.forEach {
                    contentBuilder.append(it.position3D.x)
                        .append(",")
                        .append(it.position3D.y)
                        .append(",")
                        .append(it.position3D.z)
                        .append(",")
                        .append(it.inFrameLikelihood)
                        .append(",")
                }
                contentBuilder.append("\n")
                val content = contentBuilder.toString()
                println(content)
                fileOut.appendText(content)
                
                Log.d("LOG:", "Success")
            }
            
            // 处理完成后回收Bitmap(确认后续不再使用时调用)
            if (!bm.isRecycled) {
                bm.recycle()
            }
        }
        .addOnFailureListener { 
            Log.d("LOG:", "Failure: ${it.message}")
            // 失败场景下也回收Bitmap
            if (!bm.isRecycled) {
                bm.recycle()
            }
        }
} else {
    Log.d("LOG:", if (bm == null) "null" else "skip frame for throttle")
}

额外优化建议

  • 使用LruCache缓存Bitmap,减少频繁创建与销毁的开销
  • 确保fileOut在使用完毕后正确关闭,避免IO资源泄漏
  • 在Activity/Fragment销毁时调用poseDetector.close(),释放MLKit相关资源
  • 借助Android Studio Profiler工具,定位具体内存泄漏点

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:25:17