Android 内存相关知识点记录
原文地址:https://juejin.cn/post/6844904099998089230Android 内存分配模型在Android系统中,堆实际上就是一块匿名共享内存。Android虚拟机仅仅只是把它封装成一个 mSpace,由底层C库来管理,并且仍然使用libc提供的函数malloc和free来分配和释放内存。大多数静态数据会被映射到一个共享的进程中。常见的静态数据包括Dalvik Co
原文地址:https://juejin.cn/post/6844904099998089230
Android 内存分配模型
在Android系统中,堆实际上就是一块匿名共享内存。Android虚拟机仅仅只是把它封装成一个 mSpace,由底层C库来管理,并且仍然使用libc提供的函数malloc和free来分配和释放内存。
大多数静态数据会被映射到一个共享的进程中。常见的静态数据包括Dalvik Code、app resources、so文件等等。
在大多数情况下,Android通过显示分配共享内存区域(如Ashmem或者Gralloc)来实现动态RAM区域能够在不同进程之间共享的机制。例如,Window Surface在App和Screen Compositor之间使用共享的内存,Cursor Buffers在Content Provider和Clients之间共享内存。
Dalvik
- Linear Alloc
- Zygote Space
- Alloc Space
ART
- Non Moving Space
- Zygote Space
- Alloc Space
- Image Space
- Large Obj Space
不管是Dlavik还是ART,运行时堆都分为 LinearAlloc(类似于ART的Non Moving Space)、Zygote Space 和 Alloc Space。Dalvik中的Linear Alloc是一个线性内存空间,是一个只读区域,主要用来存储虚拟机中的类,因为类加载后只需要只读的属性,并且不会改变它。把这些只读属性以及在整个进程的生命周期都不能结束的永久数据放到线性分配器中管理,能很好地减少堆混乱和GC扫描,提升内存管理的性能。Zygote Space在Zygote进程和应用程序进程之间共享,Allocation Space则是每个进程独占。Android系统的第一个虚拟机由Zygote进程创建并且只有一个Zygote Space。但是当Zygote进程在fork第一个应用程序进程之前,会将已经使用的那部分堆内存划分为一部分,还没有使用的堆内存划分为另一部分,也就是Allocation Space。但无论是应用程序进程,还是Zygote进程,当他们需要分配对象时,都是在各自的Allocation Space堆上进行。
当在ART运行时,还有另外两个区块,即 ImageSpace和Large Object Space。
- Image Space:存放一些预加载类,类似于Dalvik中的Linear Alloc。与Zygote Space一样,在Zygote进程和应用程序进程之间共享。
- Large Object Space:离散地址的集合,分配一些大对象,用于提高GC的管理效率和整体性能。
注意:Image Space的对象只创建一次,而Zygote Space的对象需要在系统每次启动时,根据运行情况都重新创建一遍。
内存泄漏
- 本地资源对象
- 注册对象(Rxjava、BordCast列表,)
- 静态对象(单例)
- 非静态内部类
- Hanlder的 looper的messageQueue
- Collection容器
- WebView
内存问题常用总结
- **内部类问题:**每个类实例都具有一个this0,当它的内类需要访问它的成员时,内类就会持有外类的 this0,通过this0,通过 this0,通过this0 就可以访问外部类所有的成员。解决方案是在 Activity 关闭,即触发 onDestory 时解除内类和外部的引用关系。
- **非静态内部Hanlder:**在外部类(如 Activity)销毁的时候使用 removeCallbackAndMessages 来移除回调和消息。
- 系统服务时产生的内存问题:使用 getSystemService 方法来获取系统服务,但是当在 Activity 中调用时,会默认把 Activity 的 Context 传给系统服务,在某些不确定的情况下,某些系统服务内部会产生异常,从而 hold 住外界传入的 Context。解决方案是 直接使用 Applicaiton 的 Context 去获取系统服务。
- **WebView 类型的泄漏:**对应 WebView 来说,其 网络延时、引擎 Session 管理、Cookies 管理、引擎内核线程、HTML5 调用系统声音、视频播放组件等产生的引用链条无法及时打断,造成的内存问题基本上可以用”无解“来形容。解决方案是我们可以 把 WebView 装入另一个进程。具体为在 AndroidManifes 中对当前的 Activity 设置 android:process 属性即可,最后,在 Activity 的 onDestory 中退出进程,这样即可基本上终结 WebView 造成的泄漏。
- **组件问题:**注册一些组件,如广播、定时器、事件总线等等。这个时候我们应该在适当的时候对组件进行注销,如 onPause 或 onDestory 方法中。
- Handler / FrameLayout 的 postDelyed 方法触发的内存问题:使用到 Handler / FrameLayout 的 postDelyed 方法时,我们需要调用 removeCallbacks 去移除实现控件内部的延时器对 Runnable 内类的持有。
- **资源目录:**如果放到分辨率低的目录如 hdpi 目录,则可能会造成内存问题,这个时候建议尽量问设计人员要高品质图片然后往高密度目录下方,如 xxhdpi 目录,这样 在低密屏上”放大倍数“是小于1的,在保证画质的前提下,内存也是可控的。也可以使用 Drawable.createFromSream 替换 getResources().getDrawable 来加载,这样便可以绕过 Android 的默认适配规则。
- 列表 item 被回收时注意释放图片的引用
- 使用 ViewStub 进行占位
- 定时清理 App 过时的埋点数据
- 匿名内部类 Runnable 造成内存泄漏的处理:
Field f = job.getClass().getDeclaredField("this$0"); f.setAccessible(true); f.set(job, null);
更多推荐
所有评论(0)