Android内存抖动

内存抖动
在Java内存管理机制中内存抖动会引起频繁的GC,从而使UI线程被频繁阻塞。内存抖动是由于短时间内有大量对象进出Young Generiation区导致的。

内存抖动的几点建议:

  • 尽量避免在循环体内创建对象,应该把对象创建移到循环体外。
  • 注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。
  • 当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。
  • 对于能够复用的对象,同理可以使用对象池将它们缓存起来。

一,内存抖动案例

开发中遇到的内存抖动问题,在做摄像头功能的时候,需要对画面重绘,用到了onPreviewFrame,看下代码实现。

public class MainActivity extends Activity implements Camera.PreviewCallback {
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private Camera mCamera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //mSurfaceView
        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view_camera2_activity);
        mSurfaceHolder = mSurfaceView.getHolder();
        // mSurfaceView添加回调
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建
                // 初始化Camera
                initCamera();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁
                // 释放Camera资源
                if (mCamera != null) {
                    mCamera.stopPreview();
                    mCamera.release();
                }
            }
        });

    }

    /**
     * SurfaceHolder 回调接口方法
     */
    private void initCamera() {
        mCamera = Camera.open();//默认开启后置
        mCamera.setDisplayOrientation(0);
        if (mCamera != null) {
            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
                //开始预览
                mCamera.startPreview();
                mCamera.setPreviewCallback(this);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        Log.e("MainActivity", "onPreviewFrame: ");
    }
}

就是这段代码引起了内存抖动,主要是因为onPreviewFrame回调产生大量byte[]导致的。当然这是我们知道问题了才说和 onPreviewFrame回调有关,假如在开发过程中发现问题,不一定就能马上定位到问题,下面就说一下,我遇到这个问题的过程。

二,遇到问题分析

1,产品需求
做一个人脸识别功能,并且要求对相机的预览画面进行重绘。
2,实现功能
这种需求肯定得对Camera 进行定制,onPreviewFrame回调取出预览数据用于人脸检测和画面绘制。
3,发现问题
在测试过程中,发现人脸识别时候出现页面卡顿现象。
4,初步预判
怀疑和人脸识别有关,查找问题往往先从出现问题的地方入手。
5,内存检测
在开发过程中,需要卡顿现象第一个想到的就是测下内存情况。
6,开始检查内存
利用强大的AndroidStudio中的Monitors检测内存,检测之后果然发现问题。这段内存出现锯齿状,这说明就是出现了内容抖动。

Android内存抖动_第1张图片

7,开始分析
利用Allocation Tracking在出现抖动的地方做记录。可以看到这里不断创建销毁的数据类型是byte[]数组。
Android内存抖动_第2张图片
打开Android Device Monitor,选中应用,点击Start Method Profiling
Android内存抖动_第3张图片

三,解决办法

1,把setPreviewCallback替换成

int size = mParams.getPreviewSize().width * mParams.getPreviewSize().height * 3 / 2;
if (mPreBuffer == null) {
    mPreBuffer = new byte[size];
}
mCamera.addCallbackBuffer(mPreBuffer);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.addCallbackBuffer(mPreviewBuffer);
mCamera.setPreviewCallbackWithBuffer(this);

在onPreviewFrame中添加

  mCamera.addCallbackBuffer(mPreviewBuffer);

Android内存抖动_第4张图片

上图所示,修改后再次测内存,抖动的情况消失。

2,这里用的是Camera,当然Android5.0之后对Camera做了优化处理,如果用新版本的Camera不会有这种问题。

你可能感兴趣的:(android知识点,Camera内存抖动)