GC这块,当java才入门的时候,老师说java不像c++,c语言需要对内存进行管理,java有垃圾回收机制,会自动进行回收,是实际的生产中也没关注过这些,现在回过头好好了解下,发现里面很有回收很多的机制。
####GC
GC(Garbage Collection)的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停。
- 对新生代的对象的收集称为minor GC;
- 对旧生代的对象的收集称为Full GC;
- 程序中主动调用System.gc()强制执行的GC为Full GC。
不同的对象引用类型, GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型:
- 强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)
- 软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)
- 弱引用:在GC时一定会被GC回收
- 虚引用:由于虚引用只是用来得知对象是否被GC
###垃圾收集算法
- 标记-清除算法
标记阶段
标记存活对象
清除阶段
统一回收所有未标记的对象
缺点
会产生内存碎片,如果空间内存碎片太多,当程序产生大对象无法在堆中找到连续空间大小存放的时候,会强制发生GC
- 复制算法
原理
内存一分为二,每次只使用其中一块,当一块内存没有连续空间存储对象的时候,会把存活下来的对象复制到另外一块内存中,然后一次性清除之前的哪块空间
优缺点
- 没有内存碎片问题
- 代价就是讲内存减少了一半,空间利用率不高
- 不适用于存活对象较多的场景,比如老年代
- 而实际上我们并不需要按照1:1的比例来划分,因为大部分对象从创建到结束这个生命周期很短
- HotSpot虚拟机默认Eden:Survivor=8:1
- 标记-整理算法
原理
- 标记存活对象,然后把存活对象向一端移动
- 清理掉存活对象这端以外的所有空间
优缺点
- 适合用于存活对象较多的场合,如老年代
- 解决了空间碎片和效率问题:将所有的存活对象压缩到内存的一端,然后清理边界外所有的空间
- 分代收集算法
分代思想
- 堆划分为新生代和老年代
- 新生代中,能够存活的对象很少,可以使用复制算法
- 老年代中,对象存活率高,而且没有额外的空间用来做老年代的担保,可以使用标记清除或者标记整理算法
###垃圾收集器-GC
- Serial 新生代串行收集器 新(复制算法),老(标记整理)
- ParNew 新生代并行收集器
- Parallel Scavenge 新生代并行收集器
- 目标:尽可能缩GC时用户线程的停顿时间
- 在注重吞吐量或CPU资源敏感的场合,可以优先考虑Parallel
- Scavenge收集器 + Parallel Old收集器
- Serial Old 老年代串行收集器
- Parallel Old 老年代并行收集器
- CMS 真正意义上的并发收集器(老年代收集器)
- 目标:最短的GC停顿时间
- G1
Trace跟踪参数
-verbose:gc
打印GC日志信息
-XX:+PrintGCDetails
打印GC日志信息
-Xloggc:d:/gc.log
GC日志目录
-XX:+PrintHeapAtGC
每次一次GC后,都打印堆信息
-XX:+TraceClassLoading
类加载信息
-XX:+PrintClassHistogram
配置了该参数后,在程序执行过程中,按下Ctrl+Break后,就可以打印类的信息
PS:其实说这么多啊,最重要的还是使用打印的方式看看那个发生内存溢出的情况与数据操作有很大的关系,有助于优化程序。