Android 内存优化(一) - 基础知识
2017-12-05 21:20
274 查看
内存结构
方法区
线程共享,存储类的信息、常量、静态变量、编译后的代码
堆区
线程共享,所有对象的实例,数组
栈区
线程私有,局部变量表,操作栈,动态链接,方法出口,对象引用
内存管理
在 Android 中我们采用的是 paging(分页) 与memory-mapping(mmapping-内存映射) 机制来管理内存的。通过这种机制我们把数据分成固定大小的区块,当需要时就从硬盘中提取出来,加载到主存中,当不需要时就移回硬盘中。内存容量
在 Android 中每一个 app 都限定了一个 heap size 的最大值。这个值会因为不同的设备而有所不同。如果 app 到达了这个值后继续申请内存的会就会引起 OutOfMemoryError 错误。我们可以通过Runtime.getRuntime().maxMemory();
来获取当前 app 可获取的最大的 heap size。
如果扩大这个最大值,可以在 AndroidManifest 的 Application 中设置
android:largeHeap="true"
通过这种方法,就能扩大 heap size 的最大值。
GC(Garbage collection)
在 app 的执行过程中我们会创建很多的对象来实现不同的功能,这么多的对象为什么没有触发 OOM 呢?这是因为 Java 为我们提供了 GC(垃圾回收)机制。它能帮助我们销毁掉不再使用的对象,为其他对象腾出空间。在这里我们讨论的是针对堆区和方法区中的GC,栈区中的空间只要利用栈来管理就行了十分方便。堆区
判断对象是否可回收
引用计数算法给每个对象添加一个引用计数器,每有一个对象引用它了,就 +1 ,失效时 -1 。当计数器为 0 的对象就是不再使用的,GC 就会对其进行回收。
这个方法很方便,但是,它很难解决对象相互循环引用的问题,如下图,即使 Instance1 已经与原有引用断开了关系,但是和其他对象形成了互相循环引用,计数器都为1,这样就不能被回。
根搜索法
这个方法利用了有向图的概念,若不能从 GC-Root 到达的对象就为可回收的对象。改,方法就解决了对象相互循环引用的问题,只要 GC-Root 不可达即视为可回收。Java 就是采用了这种方法。
GC-Root :
虚拟机栈中局部变量引用的对象
类静态属性引用的对象
常量引用的对象
JNI中引用的对象
当检测到对象不可达时,GC 不会立即对其进行回收,而是先对其进行标记。若发现没有执行 finalize 方法,就会让其进入 F-Queue 队列,开启另一个线程执行其 finalize 方法,若执行后发现它添加回 GC-Root 的引用链中了就不再理会,没有则第二次标记,然后回收。执行过 finalize 的则直接第二次标记,然后回收。
引用的分类
强引用在代码中普遍存在的
Object obj = new Object();
只要强引用还在,GC 就不会回收掉。当内存不足时,虚拟机宁愿抛出 OOM 也不回收强引用
软引用
在内存足够的情况下不回收,在内存不够用的时候才会回收
SoftReference ref = new SoftReference(new Object());
弱引用
当 GC 发生时就会被回收
WeakReference ref = new WeakReference(new Object());
虚引用
虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
方法区
回收的内容主要有:废弃的常量和无用的类- 废弃常量回收和堆中的对象回收时类似。
- 无用的类
- 该类的所有实例都已经卑回收,即堆区中无该类的任何实例
- 该类的 ClassLoader 都已经被回收
- 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
内存回收算法
标记清除(Mark-Sweep)
标记:标记出不可达对象清除:回收标记的对象
优点:简单,易实现
确定:容易产生内存碎片
适用于小对象
复制算法(Copying)
把内存区域分为容量相等的两块区域,每次只使用其中一块,当一块内存空间用完了,就把存活的对象复制到另一块中,然后把刚使用过的内存空间一次清除- 优点:简单,不会有碎片
- 缺点:空间使用率低,当存活对象多时,效率会降低。
标记整理算法(Mark-Compact)
与 Mark-Sweep 相似,只是标记后,对存活的对象进行了整理,把他们向一端移动,然后清除掉端边界以外的内存。适合存活对象多,回收对象少的情况。
分代(Generation)
结合了 Copying 和 Mark-Compact .Java 就是采用了分代收集法。年轻代(Young Generation)
新 new 出来的对象就会分配到这里,采用 minor garbage collection(Copying)
新 new 一个对象时,这个对象会分配到 Eden
当 Eden 满了的时候引用可达的对象就会进入 S0(Survivor),然后清空 Eden
当 S0 也满了后,将 S0 中引用可达的对象移入 S1 ,请空 S0 。当两个存活区切换了几次后,任存活的对象复制进老年代
Eden:S0:S1 = 8:1:1
https://img-blog.csdn.net/20171205211918658?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzE4NzY4NDE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast” alt=”” title=”” />inor_20gc.png)
老年代(Old Generation)
老年代空间会比年轻代要大,GC(Major GC|Full GC - Mark-Compact) 发生的次数也比年轻代少。大对象可直接进入老年代。
永久代(Permanent Generation)
包含应用的类/方法信息,以及 JRE 库的类和方法信息
Stop-The-World
总的来说,GC 对于内存的管理来说是十分有好处的。但是,在 GC 的过程中会暂停主线程(我们称为 stop-the-world)。我们知道,Android 所有 UI 的刷新都是在主线程上的,如果 GC 的时长过长,或频繁的GC(内存抖动)就会导致 UI 的刷新的过程卡顿,超过 16ms 这时用户就会感觉到界面的卡顿。相关文章推荐
- Android基础知识(简单实例计算器)
- android基础知识----自带的分享
- Android中,JNI技术的相关基础知识
- Android基础知识三(Activity生命周期)
- (Android 基础知识) ActionBar----顶部控件
- Android面试基础知识
- 【Android基础知识】TextView跑马灯效果
- 【Android基础知识】WebView基本用法
- 关于Android中xml文件的使用基础知识
- android开发学习---linux下开发环境的搭建&& android基础知识介绍
- (android 基础知识) android中application标签说明
- Android基础知识大纲
- Android基础知识学习——界面转换(完善)
- Android Map开发基础知识学习笔记
- Android中的一些基础知识(三)
- android Launcher基础知识
- Android手机分辨率基础知识(DPI,DIP计算)三
- 解读Android之Activity(1)基础知识
- android-基础知识解析
- Android基础知识--11.Android日志系统