在jvm中比较重要的一块就是垃圾回收,也是我们常常提到的 GC 了.
1.垃圾收集
直白说就是:怎么确定那块内存是垃圾呢?
收集方法:
1.引用计数法:对象的引用,每增加一个,那么引用的计数就++,同理每减少一个,引用的计数就–,当引用的计数为0的时候代表可以被回收优点
:简单明了缺点
:速度慢,会导致相互引用的问题
看看图
2.可达性算法:从根集(一般包括栈中引用的对象,方法区常量池中引用的对象)开始遍历,若有对象不可达,代表可以被回收.优点
: 解决了引用计数法中相互引用的问题
看看图
2.垃圾回收
1.标记清除法:先标记所有需要被回收的内存,然后统一进行清理.缺点:
效率低,会产生大量的碎片.
看看图
可以看到在 AfterGc 之后,空白位置基本没有连续的,产生了碎片.
2.复制法:将内存区域一分为二(A 和 B),只用其中的一块内存(A),当需要 Gc 的时候,把 A中 存活的对象,复制到 B 内存中,然后把 A 内存整个回收.缺点:
内存需要二块
看看图
3.标记整理法:此方法是标记清除法的一个升级版,就是在标记清除之后,把内存整理一下,去除碎片缺点:
在清除垃圾之后,还要增加一个整理的步骤
看看图
4.分代收集算法:(这也是现在的虚拟机普遍用的算法)
其实这里没有新的算法,只是用了上面的几种而已.只不过方式改变了.来看看吧.
说明:
此方法把 java Heap 分成了三个区域,分别是年轻代(Young),年老代(Old)和持久代
年轻代(Young): 这块内存又被分成了三个区域分别是 新生代(Enden),Survivo1和 Survivo2
1.Enden:所有新的对象都会在这块内存中产生
2.Survivo: 总有一块是空着的区域1或者2
具体就是新对象产生于Enden 区域,当需要 Gc 的时候,会把存活的对象复制到 Survivo1号区域中,同时清空 Enden 和 Survivo2号区域,当再次需要 gc 的时候,把 Enden 中存活的对象放到 Survivo2号区域,同时也会把 Survivo1号区域中存活的对象复制到 Survivo2号区域.然后再把 Enden 和 Survivo1清空.后续就是重复执行刚才的步骤了.
年老代( Old):
经过 n 次在 Young 的 gc 之后,依然能存活的对象,会被移动到 Old 区域.这里的 gc 不会像 Young 那么频繁.通常此区域满的时候会出发 Full GC, 回收整个堆内存
年老代( Old):
至于持久代里存放的都是周期最长,像静态变量,类相关的内容都会存储在这里
tips:
1.Survivo1和 Survivo2两个区域对称么有先后顺序
2.Eden和 Survivo 并不是1:1分配的(如: HotSpot VM 是8:1)
3.总有一块 Survivo 是空闲的
好了,关于 jvm 之内存方面就写到这里了,看完了以后相信你已经对 jvm 虚拟机方面有一个相对来说深入的了解了.