Android内存相关知识分享:

Rain

一. Java垃圾回收机制:

1.引用计数法分析:

当对象被创建或被引用时,该对象的计数器值会加1,当其被释放时会减1,但当两个对象互相引用对方时,就会造成永久不被回收.(内存泄漏由此可见)

2.可达性分析:

GCRoot可达树节点为存或对象,其余的为死亡对象。换而言之,能够通过GCRoot根节点到达的对象都被视为存活对象.

一般讲下列四点作为GCRoot:

1.虚拟机栈(帧栈中的本地变量表)中引用的对象

2.方法区中静态属性应用的对象

3.方法区中常量应用的对象

4.本地方法栈中JNI应用的对象

Java垃圾回收的几种方式:

1.标记->清理

先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

因为在清理过程中,需要清理的内存地址不是连续的,所以清理后会造成很多的内存碎片


Android top信息 ram剩余_垃圾回收

2.标记->整理

标记整理算法的“标记”过程和标记-清除算法一致,只是后面并不是直接对可回收对象进行整理,而是让所有存活的对象都向一段移动,然后直接清理掉端边界意外的内存。

由于会整理后统一进行清除,可见这样的回收方式不会造成太多的内存碎片


Android top信息 ram剩余_Java_02

标记->整理->清除这种方式比较适用于,存活多,垃圾少的情况,这样的话,对于整体内存移动和回收来说是比较节省空间的。

3.停止->复制:

将可用的内存按容量划分为大小相等的两块(from,to),每次只是用其中一块(总有一块是空的【to区域】)。当这一苦熬的内存用完了,就将还存活着的对象复制到另外一块上面,然后把已使用过的内存空间一次清理完。

Android top信息 ram剩余_Android top信息 ram剩余_03

停止,复制就意味着在一段时间内,只能使用一部分内存空间,当使用的空间超出这一半内存空间大小后,就会频繁的触发GC.

此方法适用于,存活对象少,垃圾多的情况,这样就会复制少,清空多。

Java的分代机制:

Java的堆空间一般分为三部分来存储三类数据

新生代:

存放刚刚创建的对象,代码才开始运行会创建大量对象,这些对象会统一的存放在新生代,因为有很多局部变量对象等会很快的变成不可达状态,快速死去。

特点:存活对象少,垃圾多

老年代:

存活了一段时间的对象,从创建后就一直存活下来。

特点:垃圾少,存活对象多

永久代:

一些静态文件等,Java8中已经删除并将这块区域划分给了元空间。

[外链图片转存失败(img-4M37sl2f-1565406219643)(C:\Users\XGIMI\AppData\Local\Temp\1554277085476.png)]

特点:永久存活,不回收

各个分代的垃圾回收机制:

结合上面的三种垃圾回收机制,很容易得出:

名称

特点

回收机制

新生代

垃圾多,存活少

复制

老年代

存活多,垃圾少

标记-整理-清除

新生代垃圾回收流程:

新生代在每次GC后,都会有大量不可达垃圾死去,只有少量存活。

Java新生代内存划分区域为:

[外链图片转存失败(img-I0iLnCCM-1565406219645)(C:\Users\XGIMI\AppData\Local\Temp\1554278013970.png)]

1.Edent区对外提供最大可使用内存,当Edent区快要满的时候,则触发GC,把存活的对象移植到SA中,并清空Edent

2.当Edent再次快满的时候,此时会对Ed和SA区同时触发GC,活的对象存在到SB中,同时清空Ed和SA

3.一直重复该流程,当某个S区被填充满了后且任有对象未被复制到S区,或在某个对象移植反复的被放置到S区15次左右,则把这一部分放入Old区

4.当old区也被填满后,则会触发majorGC,对old代进行GC

老年代垃圾回收流程:

因为old区,本来就是存活较久的对象,所以每次GC只会有较少部分被回收,使用标记-整理-清除,通过少量的移动就可以实现内存清理而且避免了内存碎片化。

GC的触发类型:

GC_FOR_MALLOC:

表示在堆上分配对象内存不足时触发的GC

GC_CONCURRENT:

表示当我们应用程序的堆内存达到一定量时触发的GC

GC_EXPLICIT:

应用调用system.gc …VMRuntime.gc接口时,jvm收到SIGUSR信号时触发的GC

(kill -12 12345 or kill -SIGUSR2 12345  )

GC_BEFORE_OOM:

在发生OOM时触发的GC