参考其他优秀博主博文,侵权请私聊我删掉,谢谢:
1.图解 Java 垃圾回收机制,写得非常好!
2.成为 Java GC 专家(1):深入浅出 Java 垃圾回收机制
3.成为 Java GC 专家( 2 ):如何监控 Java 垃圾回收机制
4.成为 Java GC 专家( 3 ): 如何优化 Java 垃圾回收机制
5.Java虚拟机垃圾回收(三) 7种垃圾收集器:主要特点 应用场景 设置参数 基本运行原理
6.Java垃圾回收机制
7.深入理解Java虚拟机——JVM垃圾回收机制和垃圾收集器详解
8.面试总结:java程序执行过程 + JVM内存管理 + GC垃圾回收机制
9.[Java基础]-- Java GC 垃圾回收器的分类和优缺点
10. java官方介绍
11.jvm 性能调优工具之 jstat
一. 带着以下问题去学习垃圾回收机制:(垃圾回收器)
1.什么是垃圾回收机制? 什么是自动垃圾回收?
2. java垃圾回收算法
3. 哪些内存需要回收?——who
4.什么时候回收?——when
5.怎么回收?——how
6.怎么减少gc的开销,优化.
7.JVM内存划分(内存管理)
8.jvm怎么配置gc的参数
9.常用垃圾回收机制的基本过程/流程。(回收算法)
(1).标记-清除-压缩
-
垃圾回收的第一步是标记。垃圾回收器此时会找出哪些内存在使用中(程序中有指针指向),还有哪些不是(没有被任何指针给指向)。
-
清除是指 删掉标记出的未引用对象。
-
压缩是指 为了提升性能,删除了未引用对象后,还可以将剩下的已引用对象放在一起(压缩),这样就能更简单快捷地分配新对象了。
缺点:
效率问题:标记和清除两个过程的效率都不高;(因为耗时很长)
空间问题:标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,因此标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
(2) 复制算法
将内存分为两块,每次只使用一块。当这一块内存满了,就将还存活的对象复制到另一块上,并且严格按照内存地址排列,然后把已使用的那块内存统一回收。
优点是:能够得到连续的内存空间
缺点是:浪费了一半内存
(3)分代算法
在java中,把内存中的对象按生命长短分为:
- 新生代:活不了多久就go die 了,比如局部变量 (采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集).
- 老年代:老不死的,活的久但也会go die,比如一些生命周期长的对象.(采用标记-清理/ 标记-整理 算法,因为老年代存活率高,没有额外空间对它进行分配担保)
- 永久代:千年王八万年龟,不死,比如加载的class信息
补充:
1.新生代的构成: (一个伊甸园空间(Eden )和 两个幸存者空间(Survivor ) )
一共有三个空间,其中包含两个幸存者空间。每个空间的执行顺序如下:(复制算法)
1.绝大多数刚刚被创建的对象会存放在伊甸园空间。
2.在伊甸园空间执行了第一次GC之后,存活的对象被移动到其中一个幸存者空间。
3.此后,在伊甸园空间执行GC之后,存活的对象会被堆积在同一个幸存者空间。
4.当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者空间。之后会清空已经饱和的那个幸存者空间。
5.在以上的步骤中重复几次依然存活的对象,就会被移动到老年代。
如果你仔细观察这些步骤就会发现,其中一个幸存者空间必须保持是空的。如果两个幸存者空间都有数据,或者两个空间都是空的,那一定标志着你的系统出现了某种错误。
请务必记住在对象刚刚被创建之后,是保存在伊甸园空间的。那些长期存活的对象会经由幸存者空间转存在老年代空间。
二 .需要注意:
(1)新生代和老年代存储在java虚拟机堆上 ;永久代存储在方法区上
(2)垃圾回收器是一个周期性的过程. 周期性的检查内存中的对象,一个对象没有使用, 没有会进行回收.
(3)垃圾回收操作需要消耗CPU、线程、时间等资源,所以垃圾回收操作不是实时的发生(对象死亡马上释放),而是当内存消耗完或者是达到某一个指标(Threshold,使用内存占总内存的比列,比如0.75)时,触发垃圾回收操作。
(4) 相对于年老代,通常年轻代要小很多,回收的频率高,速度快。年老代则回收频率低,耗时长。内存在年轻代里面分配,年轻代里面的对象经过多个回收周期依然存活的会自动晋升到年老代。
(5)不要试图去假定垃圾收集发生的时间,这一切都是未知的。比如,方法中的一个临时对象在方法调用完毕后就变成了无用对象,这个时候它的内存就可以被释放。
(6)Java中提供了一些和垃圾收集打交道的类,而且提供了一种强行执行垃圾收集的方法--调用System.gc(),但这同样是个不确定的方法。Java 中并不保证每次调用该方法就一定能够启动垃圾收集,它只不过会向JVM发出这样一个申请,到底是否真正执行垃圾收集,一切都是个未知数。
(7)挑选适合自己的垃圾收集器。一般来说,如果系统没有特殊和苛刻的性能要求,可以采用JVM的缺省选项。否则可以考虑使用有针对性的垃圾收集器,比如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置,有比较多的闲置资源,可以考虑使用并行标记/清除收集器。
(8)关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的,不要让自己的一个小错误导致内存出现大漏洞。
(9)尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null,暗示垃圾收集器来收集该对象,还必须注意该引用的对象是否被监听,如果有,则要去掉监听器,然后再赋空值。
(10) 垃圾收集器,收集的垃圾是: 无用的对象(临时的等等等等).
.
三. 补充关键字:
内存管理意识 程序跑起来就不断吃资源 内存泄漏 资源释放
垃圾自动回收 内存分配和管理 可达性分析
Stop-the-World (服务暂停,意味着所有线程必须等待,直到gc任务完成)
新生代复制算法 老年代标记-压缩
标记-清除( 过程有4个步骤 : 初始标记 ,并发标记,重新标记,并发清除)
gc监测工具jstat
.