createScaledBitmap创建Bitmap循环回收后内存持续增长问题求助
分析你遇到的Bitmap内存持续占用问题
我太懂这种困惑了——明明手动回收了Bitmap,内存却还是蹭蹭涨,onDraw结束后也不见回落,这其实是Android Bitmap管理和Canvas绘制机制的几个常见坑在搞鬼,咱们一步步拆解:
为什么内存会持续增长且不释放?
- Bitmap回收不是"即时生效":你调用
recycle()只是告诉系统这个Bitmap可以被回收了,但Android的垃圾回收器(GC)是被动触发的,只有当内存压力达到阈值时才会运行。如果当前内存充足,GC会延迟执行,所以你看到内存没立即降下来是正常的,但如果循环几次后内存持续飙升,那就是有其他问题了。 - 硬件加速的"隐形缓存":你以为Canvas只有屏幕尺寸的Bitmap,但开启硬件加速时,GPU会为绘制操作创建临时纹理缓存,尤其是处理放大Bitmap这种操作时,这些GPU缓存不会随着Bitmap的
recycle()一起释放,而是会被GPU暂存一段时间,导致内存占用看起来没降。 - onDraw循环的内存碎片问题:onDraw是UI线程调度的方法,频繁在里面创建、回收Bitmap会产生大量内存碎片,UI线程的GC触发会更保守(怕卡顿),所以内存碎片会持续累积,看起来就是内存一直在涨。
解决方法(按优先级排序)
- 绝对不要在onDraw里循环创建Bitmap:把Bitmap的创建移到
onSizeChanged()或者View初始化阶段,提前生成好需要的尺寸,复用同一个Bitmap。示例代码修改如下:private Bitmap mReusableScaledBitmap; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 回收旧的Bitmap,避免内存泄漏 if (mReusableScaledBitmap != null && !mReusableScaledBitmap.isRecycled()) { mReusableScaledBitmap.recycle(); } // 提前创建放大后的Bitmap,按需调整尺寸 mReusableScaledBitmap = Bitmap.createBitmap(w * 2, h * 2, Bitmap.Config.RGB_565); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 复用提前创建的Bitmap进行绘制 Canvas scaledCanvas = new Canvas(mReusableScaledBitmap); // 在这里执行你的绘制逻辑(比如绘制原图到放大的Bitmap上) // ... // 把放大后的Bitmap绘制到当前Canvas canvas.drawBitmap(mReusableScaledBitmap, 0, 0, null); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); // View销毁时彻底回收Bitmap if (mReusableScaledBitmap != null && !mReusableScaledBitmap.isRecycled()) { mReusableScaledBitmap.recycle(); mReusableScaledBitmap = null; } } - 用BitmapPool复用Bitmap:如果必须动态生成不同尺寸的Bitmap,试试
LruBitmapPool(AndroidX提供的工具),它会缓存闲置的Bitmap,避免频繁创建和回收,减少内存开销。 - 清理硬件缓存(按需):如果确定是硬件加速导致的内存问题,可以给这个View关闭硬件加速:
或者在绘制完成后调用setLayerType(View.LAYER_TYPE_SOFTWARE, null);destroyDrawingCache()清理View的绘制缓存,但注意不要频繁调用,会影响绘制性能。 - 调试阶段手动触发GC:可以在循环结束后调用
System.gc(),但这只是建议GC运行,不是强制,只适合调试时验证问题,上线代码别这么做,会影响性能。
调试技巧
用Android Studio的Memory Profiler查看内存分配:区分是Java堆还是Native堆的内存增长(Android 8.0之前Bitmap存在Native堆,之后移到Java堆),还能看到具体哪些对象在占用内存,精准定位问题。
内容的提问来源于stack exchange,提问作者Luke B.
相关产品推荐
相关产品推荐

