标签(空格分隔): Java算法
JVM内存结构主要包括: 方法区, 堆区, 程序计数器, 本地方法区, 虚拟机栈. 其中的程序计数器, 本地方法区, 虚拟机栈这三个区域是的生命周期随线程生灭, 因此不须要过多考虑这方面的GC问题.数据结构
在JDK1.2以后, Java对引用的概念进行了补充, 整体分为四类: 强引用, 软引用, 弱引用, 虚引用. 这四种引用强度逐渐减弱.多线程
Object object = new Object();
这类的引用, 只有强引用还存在, GC就永远不会收集被引用的对象.OutofMemoryError
以前), 才会被垃圾回收. 采用SoftReference
类来实现软引用.WeakReference
类来实现弱引用.PhantomRenference
类实现.为每个对象的的数据结构添加一个引用计数器, 用于统计指向该对象的引用的数量, 每当多一个引用的时候, 其引用计数器就加一, 当引用再也不指向该地址以后计数器减一. 一旦计数器的值为0,则表示没有引用指向该对象, 则对象已经死亡 (
<<
寻梦环游记>>
说的: 人真正的死亡是全部活着的人的都忘了你的时候).布局
优势:线程
缺点:3d
目前JVM的主流垃圾回收器采起的可达性分析算法, 这个算法的实质在于将一系列
GC Roots
做为初始的存活对象的集合(Live Set
), 而后从该集合出发, 探索全部能过被集合直接或间接引用的对象, 而且将其加入集合之中, 这个过程就是标记过程. 最终, 未被探索到的对象即是死亡, 是能够回收的.代理
什么是GC Roots
, 其实就是由堆外指向堆内的引用.code
可达性分析, 能够解决循环引用问题, 可是自身也存在一些问题, 好比说在多线程的状况下, 其余线程可能会更新已经访问过的对象的引用, 形成漏删. 解决方案是 进行两次可达性分析, 若是两次某对象都被标记则进行删除.对象
由名可得: 标记
->
清除. 获得须要清除的对象以后就直接进行清除.blog
优势: 速度快
缺点: 屡次GC以后, 形成大量的碎片空间. 对于须要连续存储的较大对象没法存储, OutofMemoryError
由名可得: 标记
->
清除->
移动整理. 对标记清除算法
的一次改进, 可是由于移动操做, 因此时间成本较高.
优势: 没有内存碎片.
缺点: 时间成本较高.
将可用的内存按容量分为大小两块, 每次只是用其中一块, 当这一块的内存用完了, 就将还存活着的对象复制到另外一块内存上, 而后再把已使用的内存空间清理掉.
每次当内存分配的时候空间不够的时候, 都进行复制算法进行内存整理.
优势: 实现简单, 效率高. 解决了标记清除算法致使的内存碎片问题.
缺点: 代价太大, 将内存缩小了一半. 效率随对象的存活率升高而下降.
Eden
和两块较小的Survivor
空间.Eden
和其中Survivor
空间.Eden
和Survivor
空间中存活的对象一次性的复制到另外一块Survivor
空间上.Eden
和使用过的Survivor
空间.Hotspot
默认Eden
和Survivor
的大小比例是8:1 .
分配担保:
若是另外一块Survivor
空间没有足够的内存来存放上一次新生代收集下来的存活对象, 那么这些对象则直接经过担保机制进入老年代.
当前商业虚拟机的垃圾收集器都是采用分代收集算法, 根据对象存活周期的不一样将内存划分为几块. 通常把
Java
堆分为新生代, 老年代. JVM根据各个年代的特色采用不一样的手机算法.
Java堆是JVM所管理的内存的最大的一块, 也是GC主要的工做区. 其主要分为两个区
年轻代
和老年代
, 其中年轻代又分为Eden
和Survivor
区, 其中Survivor
区又分为FROM
和To
两个区. 可能这个时候你们又会有疑问, 为何须要Survivor
区, 为何Survivor
还要分为两个区?
Eden
区 : IBM表示有98%的对象是朝生夕死, 因此针对这一现状, 大多数状况下, 对象会在新生代Eden
区中进行分配, 当Eden
区没有足够的空间进行分配的时候, 虚拟机会发起一次GC
. 经过此次GC
以后,Eden
会被清空,Eden
区中绝大部分的对象会被回收, 而那些无需回收的存货对象, 将会进到Survivor
的FROM
区(若FROM
不够, 则直接进入Old
区).
Survivor
区: 至关因而Eden
区和Old
区的一个缓冲, 相似于咱们交通中的黄灯.Survivor
又分为两个区, 一个为From
区, 一个是To
区. 每次执行Minor GC
会将Eden
区和FROM
存活的对象放到Survivor
的To
区(若是To
则直接进入Old
区).
不是新生代到老年代么, 直接中
Eden
到Old
很差了么,为何要这么复杂. 若是没有Survivor
区,Eden
区每一次GC
, 存活的对象就会被送到老年代, 老年代很快就会被填满, 而虽然有不少对象虽然一次没有被消灭掉,可是也存活不了太屡次, 这个时候将其移入Old
区会很快的将其填满.
因此
Survivor
的存在乎义就是减小被送到老年代的对象, 进而减小GC
的发生.Survivor
的筛选保证, 只有经历16此的GC还能再新生代存活的对象,才会被送到老年代.
Old区占据着
2/3
的堆内存空间,只有在Marjor GC
的时候才会进行清理, 每次GC
都会出发stop-the-world
. 内存越大,SWT
的时间也越长, 因此内存也不只仅是越大越好, 因为复制算法的对象存活率较高的老年代会进行不少次的复制操做, 效率很低, 因此老年代这里采用的是 标记整理算法.
除了上述所说, 在内存担保机制的状况下, 没法安置的对象也会直接进入老年代, 如下几种状况也会进入老年代.
Eden
区以及两个Survivor
区之间发生大量的内存复制, 当你的系统有很是多的"朝生夕死"的大对象的时候, 就值得注意了.Survivor
的FROM
和To
之间进行移动, 对象在每经历一次Minor GC
, 年龄就会自增1, 当年龄增长到15岁的时候, 就会被移入老年代. 这里的15是能够进行自定义的.Survivor
空间中相同年龄全部对象的总和大于Survivor
空间的通常, 年龄大于等于该年龄的对象就能够直接进入老年区.