java垃圾收集笔记

java垃圾收集笔记

1.jvm有clientserver两种运行模式(jdk1.5后只有server模式了),前者启动快,运行慢;后者启动慢,运行快。

2.可达性分析理解:
新建一个了IDE对象时,肯定要有一个引用指向该对象,否则这个新建的象就不能用,也就没有意义了。而指向该对象的引用一般是方法里的一个变量,它的生命周期至方法运行结束,结束后对它的引用(这里的“引用”是名词,即那个变量名)也就失效了,他也就没有被引用了。当然,静态对象,常量是另外一回事。

3.jvm通过可达性分析来判断对象的存亡。
可以作为GC Roots的对象:
(1)虚拟机(JVM)栈中引用对象
(2)方法区中的类静态属性引用对象
(3)方法区中常量引用的对象(final 的常量值)
(4)本地方法栈JNI的引用对象

4.java引用分类:
Strong Reference : 只有在引用对象root不可达的情况下才会标识为可回收,垃圾回收才可能进行回收。否则,宁可内存溢出。
Soft Reference : 无论其引用的对象是否root可达,在内存快满时,由垃圾回收判断是否需要回收(可能会被回收)。
Weak Reference :用来描述非必需对象。即使在root算法中 其引用的对象root可达到,只能生存到下一次垃圾回收之前。
Phantom Reference :无法通过虚引用获得一个对象的实例,设置虚引用的目的就是能在这个对象被收集器回收时收到一个系统通知(观察回收过程)。

5.并行:垃圾收集器启动多线程同时工作;
并发:垃圾收集器线程和用户工作线程同时工作,不用stop-the-world

6.一个系统中可以同时配置多个垃圾收集器,来分别收集老年代新生代的垃圾。因为这两个区域的垃圾收集情况不一样。

7.垃圾收集算法:
(1)标记-清除算法:先对需要清除的对象进行标记,再统一清除。
优点:不要额外空间,简单。缺点:会产生内存碎片;
(2)copy算法:把内存分为Eden区和From Survivor,To Survivor分为三部分,垃圾收集时,先把Eden存活的和From Survivor中存活的且年龄还没达到老年代的对象复制到To Survivor区,把From Survivor中存活的且年龄已达到老年代的对象复制到老年代区,再一次性清除A里所有空间(因为是连续的,只需移动栈顶指针)。
优点:内存没有碎片。缺点:复制操作影响效率,总有一块空间浪费;
适用于新生代。有担保机制,已处理万一B区空间(一般20%)不够的情况,这样的话直接进入老年代空间;
(3)标记-整理算法:类似于标记清除算法,只是不用负责,而是直接把存活的对象往前移覆盖死亡的对象。没有删除的操作了。
优点:空间完整,不用复制;缺点:需要多次移动;
适用于年老代。
(4)分代搜集算法:以上几个的综合运用,尤其是2,3的综合。

8.垃圾收集器:
serial:单线程,client模式下默认的新生代收集器,采用复制算法,适合单cpu系统;能与CMS收集器配合;
parNew:serial的多线程版,server模式下新生代收集器,采用复制算法,适合多cpu系统;能与CMS收集器配合;
parallel scavenge:和parNew差不多,多线程,采用复制算法,新生代收集器。它关注吞吐量最大化,其他的关注停顿时间最小化。吞吐量=运行代码时间/(运行代码时间+垃圾收集时间),它是一个时间段的平均量指标。而停顿时间关注的是单次停顿的时长。它能自适应调节。不能同CMS收集器配合。可同serial old和parallel old配合。
serial old:serial的老年版本,单线程,使用标记-整理算法。主要在client模式下使用老年代收集器,如果在serve模式下使用,可配合parallel scavenge使用,也可作为CMS的后备预案。
parallel old:parallel scavenge老年版本,多线程,采用标记-整理算法。吞吐量优先,配合parallel scavenge使用。
CMS(concurrent mark sweep 并发标记清除):上述都不能实现并发,最多并行。CMS可实现宏观上的并发标记。采用标记-清除算法,产生内存碎片。老年代收集器。
G1收集器:不要和别人配合,自己内部分代;可以实现并发和并行;可预测的停顿;整体采用标记-清理,局部采用复制算法,不产生内存碎片。

9.对象内存分配策略:
(1).一般对象直接在Eden去分配,如果Eden去内存不够,进行一次Minor GC;
(2).大对象(大的标准由PretenureSizeThreshod参数设定)直接进入老年代,这样做是为了避免新生代区域的大对象复制的性能开销;
(3).达到一定年龄的对象(由MaxTenuringThreshold参数设定)的对象进入年老代。
(4).以上为基本原则,还有几个特色原则:Survivor中某些相同年龄(比如都为10岁)的对象大小之和大于Survivor总空间的一半时,会把年龄大于该年龄(10岁)的对象提前放入老年代,虽然他们还没达到上述第三条定义的最大年龄;
(5).空间分配担保:
jvm进行Minor GC前会去检查老年代最大的连续空间是否大于新生代所有对象大小之和。之所以要检查,是因为这批新生代的对象理论上有可能都会同时进入老年代,怕老年代空间不够。当然,这是一种十分保守的做法,因为一般不会同时进入年老代,所以jvm就提供了一种不那么保守的设置,通过设置HoldPromotionFailure值来启动空间担保。但开启这个担保后,他会以之前的每次进入老年代的经验值(而不是粗暴的新生代的所有对象大小)来做是否Full GC的决策依据。这样做的目的是为了减少Full GC的次数。

10.除了堆区,垃圾收集器还收集永久代(方法区)的垃圾;
永久代的回收有两种:常量池中的常量,无用的类信息。常量的回收很简单,没有引用了就可以被回收。对于无用的类进行回收,必须保证3点:
(1).类的所有实例都已经被回收
(2).加载类的ClassLoader已经被回收
(3).类对象的Class对象没有被引用(即没有通过反射引用该类的地方)

11.内存溢出内存泄漏:
内存泄露:广义并通俗的说,就是:不再会被使用的对象的内存不能被回收,就是内存泄露。它不是一个绝对意义上的泄漏,只是回收的时间可能比理想中晚了,导致没用了还一直占着内存,也许之后的某个时刻还是肯能被回收的。一般出现在一个长生命周期的对象A持有短生命周期的对象引用B,导致B实际没用了以后还是不能被回收。防止这种结果的方法是手动用代码结束引用,比如设为null,尽量让他的作用域变小,调用close()方法等;
内存溢出:指内存不够用了,可能是因为本身系统太复杂,配置太低,也可能是因为有内存泄漏造成的。

12.OutOfMemoryError*Error:
OutOfMemoryError:指因为内存溢出,JVM不能分配给对象的创建空间.并且GC也不能够回收足够的空间.当你创建对象的速度快于JVM回收空间的时候就会发生空间不足这个问题;
*Error:一般是因为递归太深,栈的调用层级太多;

11.垃圾收集参数设置
java垃圾收集笔记
java垃圾收集笔记