1.OOM篇

https://mp.weixin.qq.com/s/GFnWqYmEih6LMBLU52jTmw
OOM全称Out Of Memory,导致这一异常主要有以下三类原因:
1.线程数太多;
2.打开太多文件;
3.内存不足;

1.1线程数太多

系统对每个进程的线程数是有限制的,当线程数超过这个限制后,就会出发OOM,不同的设备限制不一样,低端一点的手机上这个限制会更小,所以就更容易出现OOM问题。为了解决这个问题导致OOM,思路就是要降低线程数的峰值。

常规一点的方案是统一线程管理库,通过代码review的方式禁止使用new thread创建线程,但是这样的方式对开发人员有要求,也增加了代码review的工作量,而且对于三分库不起作用。
所以就需要有新的思路来解决这些问题,我们知道,在Android中创建线程主要是通过以下几种方式:
1.Thread及其子类;
2.ThreadPoolExecutor及其子类、Executors、ThreadFactory实现类;
如果将创建线程的指令,在编译期通过ASM修改字节码的方式替换成自定义的方法,就可以实现统一项目线程池。
在自定义线程池中,设置合理的线程池参数,比如核心线程设置为1或者是0,最大线程池数量设置2*NCPU+1。

1.2打开太多文件

Android是基于Linux内核,/proc/pid/limits描述了系统对每个进程的一些资源限制,其中Max_open_files指的就是最大打开文件数。当打开的文件数超过规定数目后,就会触发OOM,对于这个问题一般是监控为主,当文件打开数大于1000,或者连续递增超过50,触发信息收集,以便定位问题。

1.3内存不足

导致OOM的最主要很常见原因就是内存不足,当需要创建新的对象时,虚拟机的堆内容不足以创建对象,且发生GC后还是不够,就会抛出OOM异常。这一块的优化主要有两点,图片加载优化、内存泄露监控。

图片加载优化
为了避免图片加载导致的OOM,有以下三个点可以做优化:
1.软引用;
对于大内存对象Bitmap,可以通过SoftReference修饰,当发生GC后依然内存不够时,会回收软引用数据;
2.onLowMemory;当内存不足的时候,Application,Activity,Fragment都会调用onLowMemory方法,可以在这个方法下清除缓存,释放内存。Glide就有使用这种方式。
3.Bitmap像素存储位置;Bitmap之所以占用内存大,是因为Bitmap的像素数据,
Bitmap像素数据=宽1像素占用内存
1像素占用多少内存,是和Bitmap的格式有关的,比如使用RGB_565格式,1像素占用2byte,ARGB_8888格式,则占用4byte。所以可以考虑使用内存占用较少的格式。至于宽高,一些大图可以使用缩放后的宽高。
Android7.0之前,Bitmap是在java堆里面分配内存的,而8.0之后,是在native,所以8.0之后比较少因为bitmap引起OOM。

1.4内存监控

线下监控,LeakCanary;
线上监控,KOOM,原理和LeakCanary差不多,流程是:
虚拟机supend-》fork虚拟机进程-》虚拟机resume-》dump内存镜像