一、Android系统的内存分配和回收方式
- 一个App通常就是一个进程,对应一个虚拟机
- GC只有在Heap剩余空间不够时,才触发垃圾回收
- GC触发时,所有线程都会被暂停
二、APP的内存限制
- 每个APP分配的最大内存限制,随着设备不同而不同
- 吃内存大户:图片
三、切换应用时后台APP清理机制
- App之间切换时,内存管理使用LRU算法(最近使用的排在最前面,最少可能被清理掉)
- onTrimMemory方法:当系统内存变化时,会调用该回掉方法。该方法会得到当前内存级别,我们可以根据级别来提前管理内存(例如当内存不够时,清理app的内存,可以降低被系统清理的可能)
四、内存监控的几种方法
- AS代码输出内存信息
stringBuilder.append("memClass: " + memClass + "\n");
float totalMemory = Runtime.getRuntime().totalMemory() * 1.0f / (1024*1024);
float freeMemory = Runtime.getRuntime().freeMemory() * 1.0f / (1024*1024);
float maxMemory = Runtime.getRuntime().maxMemory() * 1.0f / (1024*1024);
stringBuilder.append("maxMemory: " + maxMemory + "\n");
stringBuilder.append("totalMemory: " + totalMemory + "\n");
stringBuilder.append("freeMemory: " + freeMemory + "\n");
Log.d("newApp", stringBuilder.toString());
- Android Studio再带的监控:Android Monitor(它可以监控内存(分配的总内存和空闲内存)、CPU和网络的情况)
3.更详细的检测工具:Android Device Monitor。
它可以监控推内存的变化(只需点击Gause GC触发垃圾回收器,就可以查看当前heap内存情况)
五、内存优化方法
- 数据结构
- 拼接大量字符串时用StringBuilder
- ArrayMap、SparseArray替换HashMap
- 内存抖动:
- 原因:反复申请大量内存,每次申请完很快就弃之不用;这时候若heap内存不够,GC就会对弃之不用的内存进行回收,内存再次变小;频繁的出现内存不断变化就是内存抖动
- 解决方案:将重复使用的变量放在外面(即更大的变量作用域或全局作用域中)
- 再小的class耗费0.5KB
- 对象的复用
- 复用系统资源
- ListView/GridView/RecyclerView的ContentView的复用
- 避免再onDraw方法里面进行对象的创建
-
避免内存泄漏
-
内存泄漏是什么?
申请一块内存(如创建对象),不再使用时GC会回收;但由于代码问题,依然被其它东西引用着,导致无法回收 -
严重后果?
内存泄漏会导致剩余的可用heap越来越少,并且频繁的触发GC -
举一个内存泄漏的例子,说一下内存泄漏原因和解决方法
- 例子:点击按钮开启一个永不停止的线程(该线程类是Activity的内部类),退出Activity,反复这个过程
- 原因:Activity的内部类会隐含的引用当前Activity,若Activity退出时,线程仍然运行,则Activity由于被这个线程引用而无法被GC回收
- 解决方法:
1. 线程创建在Service中,让service来管理,service由于长期后台运行,不会发生service关闭而线程仍然运行的情况。
2. 使用软引用或者弱引用来处理Activity内部类中对当前Activity的引用
- 内存泄漏主要是Activity泄漏
- 用Application的Context而不是Activity Context(如网络请求回掉方法中的土司框的Context用Application的Context)
- 数据库操作发生内存泄漏:Cursor对象是否及时关闭
六、OOM问题的优化
1.分析:
- OOM是内存溢出(Out Of Memory的缩写)
- OOM的必然性:每个App运行有一个内存上限
- OOM主要是图片
- 强引用、软引用、弱引用
- 强引用在变量的生命周期中不会被回收
- 软引用在变量的生命周期中只要内存不够就会被回收
- 弱引用在变量的生命周期中只要触发GC就可能被回收
- 解决OOM问题的方法:
- 临时Bitmap对象的及时回收(recycle)
- 避免Bitmap浪费
- try catch大内存分配操作的代码块(不推荐,不能解决根本问题:内存分配失败时,此方法只能防止程序崩溃,不能让程序顺畅运行)
- 最优方法,在加载Bitmap时,使用
- 缩放:设置Options调整缩放比例
- 解码格式:将默认的ARGB_8888换成RGB_565来显示图片
- 局部加载:使用BitmapRegionDecoder
- 软引用:
- LRU算法:
网友评论