JVM总结(一)

JVM总结(1)

1、JVM组成:

JVM由类加载器子系统、运行时数据区、执行引擎以及本地方法接口组成。

 

2、JVM运行原理:

Java源文件经编译器,编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。

 

3.Java垃圾回收区域

Java垃圾回收只针对堆和方法区的内存。

线程方法区、虚拟机栈和程序计数器随着线程而生,随线程而灭因此不用管。

 

4.如何确定垃圾

采取引用计数是否可行?即统计有多少人引用了,如果0人引用,则判断为垃圾。缺点是:东西很多时,消耗太大;环形引用:A引用了B,B引用了A,其实A\B都是垃圾,但他们引用永远都是1,不会被回收掉,陷入了死循环。

可达性算法:从垃圾回收的根出发判断是否可见,这也是JVM采用的可达性分析算法。

 
 

如图object5,6,7都是可回收的垃圾

 

5.垃圾回收算法

标记--清除算法:缺点碎片化很严重,导致程序运行时需要分配较大的对象时,无法找到足够的内存存放,不得不提前再进行一次GC

标记--整理算法:缺点是实际消耗很大,垃圾是一块一块的,要把回收空出的内存向前移动,不能整块移动,需要切成很多小块移动,所以消耗很大。

 

拷贝算法:先把内存分为两块,内存1往内存2拷贝,内存1全部清除,缺点是内存只能使用一般,浪费性能。

JVM实际使用的分代垃圾回收算法,就是把上面的的朴素算法综合一下

基础假设:大部分对象只存在很短的时间,这个假设确实也是对的

基于上面的假设,JVM将内存分为新生代和老生代。大部分只存在很短的时间,就放在新生代。对于少部分存在很长时间的对象,放在老生代去。

对新生代和老生代采取不同的做法

 

新生代经常性进行GC,因此要优化性能,采取类似Copy算法

将新生代分为Eden,Survivor1和Survivor2。

 

Eden是要回收的区域。1表示存活了1次垃圾回收,2表示存活了2次垃圾回收。

第一次回收,从Eden回收存活下来的对象放入Survivor1,然后清掉Eden。

又产生了垃圾

第二次回收,从Eden和Survivor1存活的对象放入Survivor2

清理掉eden和survivor1,如此反复进行,当survivor不够用时,就把survivor中年纪大的对象放入老生代
Full GC是对老生代进行GC,使用的是标记--整理算法

 

6、内存分配与回收策略

对象优先在Eden区分配

老年GC(full GC/Major GC)一般比新生代GC(Minor GC)慢十倍以上

大对象直接进入老年代,大对象是指需要大量连续内存空间的Java对象,比如很长的字符串或者数组。

长期存活的对象将进入老年代。默认15岁

动态对象年龄判定。如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。

空间分配担保:当出现大量对象Minor GC后仍然存活的情况,需要老年代进行分配担保,让Survivor无法容纳的对象直接进入老年代。

 

JVM垃圾回收参数

 

持久代(JDK8改进成元空间)

 

如何解决OutOfMemoryError:PermGen Space的问题?

使用-XX:MaxPermSize调整,调大一点

Java 1.8帮我们做了改进,取消了持久代,改进成元空间

 

元空间

 

调用String.intern()方法的时候,会将共享池中的字符串与外部的字符串(s)进行比较,如果共享池中有与之相等的字符串,则不会将外部的字符串放到共享池中的,返回的只是共享池中的字符串,如果不同则将外部字符串放入共享池中,并返回其字符串的句柄(引用)-- 这样做的好处就是能够节约空间

一个初始时为空的字符串池,它由类 String 私有地维护。 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。 它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true

 

谈谈Java垃圾回收机制

回答垃圾回收在什么时候运行?JVM分配内存失败的时候会运行。还可以手动调用System.gc(),JVM会知道你想垃圾回收了,至于到底是否进行GC由JVM自行判断,一般都是进行的。

垃圾回收对什么对象进行回收?从垃圾回收的根节点出发,看的见的不回收,看不见的都回收。

垃圾回收算法对内存划分成了哪些区域?新生代、老生代、Metaspace(元空间),新生代又分为了Eden、Survivor1、Survivor2。并回答具体的算法。

 
 

7、垃圾回收器

Serial,单线程,GC的时候必须暂停其他所有工作线程。JVM Client模式下的默认新生代收集器

ParNew,Serial的多线程版本。JVM Server模式下的默认新生代收集器。实现了GC线程与工作线程同时工作。举例就是,一边打扫卫生的时候,还可以一边往地上扔纸屑。

单CPU环境中,ParNew绝对不会有比Serial更好的效果。

Serial和ParNew都是与CMS配合工作。

Parallel Scavenge,关注“吞吐量”。比如JVM总共运行了100分钟,其中GC花了1分钟,那吞吐量就是99%。

新生代的垃圾收集器都是“复制”算法。

Serial Old,单线程,使用“标记-整理”算法负责老年代。

Parallel Old ,多线程,“标记-整理”,和Parallel Scavenge同时使用提高“吞吐量”。

CMS,并发,唯一的“标记-清除”因此可能导致老年代碎片化严重,无法容纳新生代提升上来的大对象,从而CMS失败,退回到Serial Old算法,导致GC时间过长,可以尝试调大Survivor的空间和调整 CMS 垃圾收集在老年代占比达到多少时启动来减少问题发生频率,越早启动问题发生频率越低,但是会降低吞吐量,具体得多调整几次找到平衡点;另外,如果GC频率太快,说明空间不足,首先可以尝试调大新生代空间和晋升阈值,专注最短GC停顿时间,使网站响应更快,服务不会出现长时间停滞。

G1,多线程,分代收集,“标记-整理”,可预测的停顿。如果追求低停顿,可以尝

posted @ 2019-08-10 16:02  家铭  阅读(292)  评论(0编辑  收藏  举报