1,java内存使用划分
堆内存(Heap Memory): 存放Java对象 非堆内存(Non-Heap Memory): 存放类加载信息和其它meta-data 其它(Other): 存放JVM 自身代码等。内存回收(GC)主要处理的是堆内存。
2,堆内存模型
堆内存分为两大部分:新生代和老年代。比例为1:2。新生代又分为三个部分:一个Eden区和两个Survivor区,比例为8:1:1。 Eden区存放新生的对象。 Survivor存放每次垃圾回收后存活的对象。
3,垃圾判断算法
引用计数算法
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。
可达性分析算法(根搜索算法)
从GC Roots(每种具体实现对GC Roots有不同的定义)作为起点,向下搜索它们引用的对象,可以生成一棵引用树,树的节点视为可达对象,反之视为不可达。
该算法可以解决循环引用问题。因为即使在循环引用状态下,根节点是无法找到这些节点的。
4,垃圾回收相关概念
Stop The World
Android执行垃圾回收算法时需要Stop The World(STW)。当stop-the-world 发生时,除GC所需的线程外,所有的线程都进入等待状态,直到GC任务完成。
GC执行时机
新生代的伊甸园空间(Eden)不够存放新对象的时候,执行 Minro GC 。
升到老年代的对象大于老年代剩余空间的时候(或者小于的时候被 HandlePromotionFailure 参数强制)执行 Full GC 。
5,垃圾回收算法
标注清理回收(Mark and Sweep GC)
从GC Roots开始,将内存整个遍历一次,保留所有可以被GC Roots直接或间接引用到的对象,剩下的对象当作垃圾进行回收。
拷贝回收(Copying GC)
为了解决Mark-Sweep算法内存碎片化的缺陷而被提出的算法。将内存等分,每次只是用其中的一块。当这一块内存满后将尚存活的对象复制到另一块上去,然后把整块内存的数据清除。
标注整理回收(Mark and COMPACT GC)
结合了以上两个算法,为了避免缺陷而提出。标记阶段和Mark-Sweep算法相同,标记后不是清理对象,而是将存活对象移向内存的一端,然后清除端边界外的对象。
逐代回收法(Generational GC)
标注法最大的问题就是中断的时间过长,此算法是对标注法的优化基于下面几个发现:
大部分对象创建完很快就没用了 – 即变成垃圾;
每次GC收集的90%的对象都是上次GC后创建的;
如果对象可以活过一个GC周期,那么它在后续几次GC中变成垃圾的几率很小,因此每次在GC过程中反复标注和处理它是浪费时间。
老年态内存不满时,只对新生代进行GC,当老年态内存满时再对老年态内存GC。
Android内存回收算法
Delvik
实现了标注与清理(Mark and Sweep)和拷贝GC,但是具体使用什么算法是在编译期决定的,无法在运行的时候动态更换。关于Android ART 垃圾回收机制,将在下篇文章详聊。
ART
ART运行时与Dalvik虚拟机一样,都使用了Mark-Sweep算法进行垃圾回收,因此它们的垃圾回收流程在总体上是一致的。但是ART运行时对堆的划分更加细致,因而在此基础上实现了更多样的回收策略。
两种可能会触发GC的情况。第一种情况是没有足够内存分配请求的分存时,会调用Heap类的成员函数CollectGarbageInternal触发一个原因为kGcCauseForAlloc的GC。第二种情况下分配出请求的内存之后,堆剩下的内存超过一定的阀值,就会调用Heap类的成员函数RequestConcurrentGC请求执行一个并行GC。
网友评论