在Java语言中,程序员通过关键字new来创建对象,当使用完创建出来的对象后,程序员无需手动释放内存。这部分释放内存的工作就叫做垃圾收集,由JVM来承担。
JVM将内存划分为几个区域:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区(JDK8中已被废弃,采用名为MetaSpace的区域来替代,这部分内存使用native memory即本地内存)。以上的==程序计数器、Java虚拟机栈、本地方法栈不用考虑回收问题==。因为都是线程私有的区域,随着线程的产生而产生、线程的销毁而销毁,并且这部分空间大小的分配、回收,在编译期间就可以确定,当方法结束或者线程结束时进行回收。
Java堆和方法区(==JDK8改为MetaSpace,这部分待查阅资料后补充==),由于一个类的不同实现类需要的内存不一样,一个方法的多个分支创建的对象也不同,这一部分内存在编译期是不确定的,只有真正运行程序时才能明确。==Java堆和方法区,这部分内存的分配和回收都是动态的,垃圾回收机制也是在这一个区域内讨论==
在垃圾收集之前,必须先知道哪些对象不再被任何其他途径使用了。垃圾收集器进行处理的也是这一类对象。
为对象保存一个引用计数器,当对象被一个地方引用时,就将这个计数器加一,有一个地方取消引用时,就将计数器减一。任何时刻计数器为0,就说明这个对象不可能再被使用
可达性分析(Reachability Analysis)通过一系列的”GC Root”的对象作为起始点,从这些节点向下搜索,经过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连的话,这个对象不可达。判定为可以被回收的对象
强引用、软引用、弱引用、虚引用
==为什么要进行两次标记??==
方法区回收的是:废弃的变量、无用的类
几种收集算法的思想、优缺点和发展过程
分为标记、清除两个阶段。
将内存按容量分为两块同样大小的区域,每次只使用其中一块。当一块内存用完就将存活的对象复制到另一块区域中,之后清除上一块区域的空间。
复制算法在对象存活率高的情况,需要较多的复制操作,效率变低。
标记-整理的标记过程和标记-清除算法的标记过程一致,只是在标记之后,并不是进行清除操作,而是让所有存活对象都向一端移动。最后直接清除边界以外未被存活对象占用的空间。
复制算法和标记-整理算法,都具有不同的优点和缺点,并且适用于不同的场景。现代虚拟机采用分代收集算法,在不同存活周期的对象区域应用这两种收集算法(复制、标记-整理)。
由于新生代对象的存活率较低,因此适用于使用复制算法。而且新生代内存区域分为一个Eden区、两个Survivor区。每次只使用一个Eden区、一个Survivor区(这两个区域的内存与新生代内存区域总量占比默认为8:1)
老年代对象存活率较高,因此采用标记-整理算法减少复制过多对象的情况
单线程,使用复制算法,用于回收新生代的收集器。 触发GC时,Stop The World
使用场景:
多线程,使用复制算法,用于回收新生代的收集器。其实就是Serial收集器的多线程版本。默认启用与服务器相同核心的线程数;触发GC时,Stop The World
使用场景:
多线程,使用复制算法,用于回收新生代的收集器,以吞吐量为目标。(吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
关键参数:
Serial的老年代版本,使用标记-整理算法,用于回收老年代的收集器。与Parallel Scavenge搭配使用;==作为CMS收集器发生Concurrent Model Failure时的后备预案==
Parllel Scavenge的老年代版本,使用标记-整理算法。在JDK1.6中提供,==与Parallel Scavenge搭配使用,在注重吞吐量以及CPU资源敏感的场合优先考虑==
基于标记-清除算法,以获取最短回收停顿时间为目标的收集器。适用于互联网网站、B/S系统的服务端场景
缺点:
参考美团技术团队
参考 www.fasterj.com
在JVM中的进程名 | 用于收集哪个内存区域 | 启用命令行参数 | 描述 | 组合搭档
—|—|—|—|—
Copy | 新生代 | -XX:+UseSerialGC | 使用复制算法,单线程收集 | MarkSweepCompact
PS Scavenge | 新生代 | -XX:+UseParallelGC | 使用复制算法,多线程并发收集 | PS MarkSweep
ParNew | 新生代 | -XX:+UseParNewGC | 使用复制算法,多线程并发收集 | MarkSweepCompact
G1 Young Generation | 新生代 | -XX:+UseG1GC | 整体是标记-整理算法,region之间使用复制算法 | G1 Mixed Generation
MarkSweepCompact | 老年代 | -XX:+UseSerialGC | 使用标记-清除算法,可选的整理算法,单线程收集
PS MarkSweep | 老年代 | -XX:+UseParallelOldGC | 多线程标记-整理算法
ConcurrentMarkSweep | 老年代 | -XX:+UseConcMarkSweepGC | 标记-清除算法并发收集,较短的Stop-The-World时间,如果发生Concurrent-Mode-Failure时,使用MarkSweepCompact收集器作为预案
G1 Mixed Generation | 老年代 | -XX:+UseG1GC | 使用’Garbage First’ 算法
// 通过MXBean来获取垃圾收集器的信息 List<GarbageCollectorMXBean> beans = ManagementFactory.getGarbageCollectorMXBeans(); for (GarbageCollectorMXBean bean : beans) { System.out.println(bean.getName()); }
环境
java -XX:+PrintCommandLineFlags -version
输出结果为
PS Scavenge PS MarkSweep