一、Java虚拟机原理java
所谓虚拟机,就是一台虚拟的机器。他是一款软件,用来执行一系列虚拟计算指令,大致上虚拟机能够分为系统虚拟机和程序虚拟机, 大名鼎鼎的Vmare就属于系统虚拟机,他彻底是对物理计算的仿真,提供了一个能够运行完整操做系统的软件平台。程序虚拟机典型代码就是Java虚拟机,它专门为执行单个计算程序而计算,在Java虚拟机中执行的指令咱们称为Java字节码指令。不管是系统虚拟机仍是程序虚拟机,在上面运行的软件都被限制于虚拟机提供的资源中。到如今引用最普遍的是HotSpot虚拟机c++
二、Java内存结构程序员
三、Java堆算法
堆内存用于存放由new建立的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还能够在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,之后就能够在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量至关于为数组或者对象起的一个别名。数组
根据垃圾回收机制的不一样,Java堆有可能拥有不一样的结构,最为常见的就是将整个Java堆分为新生代和老年代。其中新生代存放新生的对象或者年龄不大的对象,老年代则存放老年对象。新生代分为den区、s0区、s1区,s0和s1也被称为from和to区域,他们是两块大小相等而且能够互相角色的空间。绝大多数状况下,对象首先分配在eden区,在新生代回收后,若是对象还存活,则进入s0或s1区,以后每通过一次新生代回收,若是对象存活则它的年龄就加1,对象达到必定的年龄后,则进入老年代。缓存
四、Java栈 服务器
java虚拟机也是线程私有的,它的生命周期和线程相同。虚拟机栈描述的是Java方法执行的内存模型:每一个方法在执行的同时都会建立一个栈帧(Stack Frame)用于存储局部变量表、操做数栈、动态连接、方法出口等信息。局部变量表存放了编译期可知的各类基本数据类型(8个基本数据类型)、对象引用(地址指针)、returnAddress类型。局部变量表所需的内存空间在编译期间完成分配。在运行期间不会改变局部变量表的大小。网络
这个区域规定了两种异常状态:数据结构
Java栈是一块线程私有的空间,一个栈通常由三部分组成:局部变量表、操做数据栈和帧数据区多线程
五、本地方法栈(Native Method Stack)
本地方法栈与虚拟机栈所发挥做用很是类似,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的native方法服务。
六、Java方法区
Java方法区和堆同样,方法区是一块全部线程共享的内存区域,他保存系统的类信息。好比类的字段、方法、常量池、静态变量、即时编译器编译后的代码等。方法区的大小决定系统能够保存多少个类。若是系统定义太多的类,致使方法区溢出。虚拟机一样会抛出内存溢出的错误。方法区能够理解为永久区,它有个别命叫Non-Heap(非堆)。
七、运行时常量池(Runtime Constant Pool)
运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各类字面量和符号引用,这部份内容将在加载后进入方法区的运行时常量池中存放。
八、直接内存(Direct Memory)
直接内存不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。但这部分区域也被频繁使用,并且也可能致使OutOfMemoryError异常。在JDK1.4中新加入的NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可使用Native函数库直接分配堆外内存,而后经过一个存储在java堆中的DirectByteBuffer对象做为这块内存的引用进行操做。
九、程序计数器(Program Counter Register)
程序计数器是一块较小的内存空间,它能够看做是当前线程所执行的字节码的行号指示器。
十、执行引擎
虚拟机核心的组件就是执行引擎,它负责执行虚拟机的字节码,通常先进行编译成机器码后执行。
十一、什么是虚拟机参数配置
在虚拟机运行的过程当中,能够跟踪系统的运行状态,对于问题的故障排查会有必定的帮助,在虚拟机提供了一些跟踪系统状态的参数,使用给定的参数执行Java虚拟机,就能够在系统运行时打印相关日志,用于分析实际问题。咱们进行虚拟机参数配置,其实就是围绕着堆、栈、方法区、进行配置。
堆的参数配置:
-XX:+PrintGC 每次触发GC的时候打印相关日志
-XX:+UseSerialGC 串行回收
-XX:+UseG1GC 应用G1收集器,最新的收集器
-XX:+PrintGCDetails 更详细的GC日志
-Xms 堆初始值
-Xmx 堆最大可用值,咱们能够直接将初始的堆大小与最大堆大小相等,这样的好处是能够减小程序运行时垃圾回收次数,从而提升效率
-Xmn 新生代堆最大可用值,通常设为整个堆的1/3到1/4左右
-XX:NewRatio 设置新生代和老年代的比例,老年代/新生代
-XX:SurvivorRatio 用来设置新生代中eden空间和from/to空间的比例,SurvivorRatio=eden/from=den/to
-XX:PermSize JVM初始分配的非堆内存 。JDK8后换成Metaspace(元空间)
-XX:MaxPermSize JVM最大容许分配的非堆内存。MaxMetaspaceSize(最大元空间)
-Xss 设置栈内存大小(设置最大调用深度),栈溢出产生于递归调用,解决办法:设置线程最大调用深度
十二、JVM参数调优总结
在JVM启动参数中,能够设置跟内存、垃圾回收相关的一些参数设置,默认状况不作任何设置JVM会工做的很好,但对一些配置很好的Server和具体的应用必须仔细调优才能得到最佳性能。经过设置咱们但愿达到一些目标:
前两个目前是相悖的,要想GC时间小必需要一个更小的堆,要保证GC次数足够少,必须保证一个更大的堆,咱们只能取其平衡。
1三、垃圾回收机制概述
Java语言中一个显著的特色就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候再也不须要考虑内存管理。因为有个垃圾回收机制,Java中的对象再也不有“做用域”的概念,只有对象的引用才有“做用域”。垃圾回收能够有效的防止内存泄露,有效的使用空闲的内存。
内存泄露是指该内存空间使用完毕以后未回收,在不涉及复杂数据结构的通常状况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序须要它的时间长度,咱们有时也将其称为“对象游离”。
1四、垃圾回收简要过程
这里必须点出一个很重要的误区:不可达的对象并不会立刻就会被直接回收,而是至少要通过两次标记的过程。
第一次被标记过的对象,会检查该对象是否重写了finalize()方法。若是重写了该方法,则将其放入一个F-Query队列中,不然直接将对象加入“即将回收”集合。在第二次标记以前,F-Query队列中的全部对象会逐个执行finalize()方法,可是不保证该队列中全部对象的finalize()方法都能被执行,这是由于JVM建立一个低优先级的线程去运行此队列中的方法,极可能在没有遍历完以前,就已经被剥夺了运行的权利。那么运行finalize()方法的意义何在呢?这是对象避免本身被清理的最后手段,若是在执行finalize()方法的过程当中,使得此对象从新与GC Roots引用链相连,则会在第二次标记过程当中将此对象从F-Query队列中清除,避免在此次回收中被清除,恢复成了一个“正常”的对象。但显然这种好事不能无限的发生,对于曾经执行过一次finalize()的对象来讲,以后若是再被标记,则不会再执行finalize()方法,只能等待被清除的命运。以后GC将对F-Queue中的对象进行第二次小规模的标记,将队列中从新与GC Roots引用链恢复链接的对象清除出“即将回收”集合。因此此集合中的内容将被回收。
1五、手动GC回收
package com.zhang.jvm; public class JVMDemo05 { public static void main(String[] args) { JVMDemo05 jvmDemo05 = new JVMDemo05(); jvmDemo05 = null; System.gc(); } protected void finalize() throws Throwable { System.out.println("gc在回收对象..."); } }
1六、finalize做用
Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,作必要的清理工做。这个方法是由垃圾收集器在肯定这个对象没有被引用时对这个对象调用的。它是在Object类中定义的,所以全部的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其余清理工做。finalize()方法是在垃圾收集器删除对象以前对这个对象调用的。
1七、内存泄露
对象已经没有被应用程序使用,可是垃圾回收器没办法移除它们,由于还在被引用着。 下面图中能够看出,里面有被引用对象和未被引用对象。未被引用对象会被垃圾回收器回收,而被引用的对象却不会。未被引用的对象固然是再也不被使用的对象,由于没有对象再引用它。然而无用对象却不全是未被引用对象。其中还有被引用的。就是这种情况致使了内存泄漏。
1八、如何防止内存泄露
一、静态集合类引发内存泄露:
像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的全部的对象Object也不能被释放,由于他们也将一直被Vector等引用着。
Static Vector v = new Vector(10); for (int i = 1; i<100; i++) { Object o = new Object(); v.add(o); o = null; }// //...对v的操做 v= null; //...与v无关的其余操做
在这个例子中,循环申请Object 对象,并将所申请的对象放入一个Vector 中,若是仅仅释放引用自己(o=null),那么Vector 仍然引用该对象,因此这个对象对GC 来讲是不可回收的。所以,若是对象加入到Vector 后,还必须从Vector 中删除,最简单的方法就是将Vector对象设置为null。
二、当集合里面的对象属性被修改后,再调用remove()方法时不起做用。
public static void main(String[] args) { Set<Person> set = new HashSet<Person>(); Person p1 = new Person("唐僧","pwd1",25); Person p2 = new Person("孙悟空","pwd2",26); Person p3 = new Person("猪八戒","pwd3",27); set.add(p1); set.add(p2); set.add(p3); System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:3 个元素! p3.setAge(2); //修改p3的年龄,此时p3元素对应的hashcode值发生改变 set.remove(p3); //此时remove不掉,形成内存泄漏 set.add(p3); //从新添加,竟然添加成功 System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素! for (Person person : set) { System.out.println(person); } }
三、单例模式
单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),若是单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,致使内存泄露
class A{ public A(){ B.getInstance().setA(this); } .... } //B类采用单例模式 class B{ private A a;//B中持有A对象 private static B instance=new B(); private B(){} public static B getInstance(){ return instance; } public void setA(A a){ this.a=a; } //getter... }
显然B采用singleton模式,它持有一个A对象的引用,而这个A类的对象将不能被回收
1九、新生代与老年代
Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各类类的实例对象。堆被划分红两个不一样的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。这样划分的目的是为了使 JVM 可以更好的管理堆内存中的对象,包括内存的分配以及回收。默认的新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值能够经过参数 –XX:NewRatio 来指定 )其中新生代 ( Young )被细分为Eden和两个Survivor区域,这两个Survivor 区域分别被命名为 from 和 to。默认的Edem : from : to = 8 : 1 : 1 ( 能够经过参数 –XX:SurvivorRatio 来设定 )
垃圾回收算法
20、根搜索法——判断对象是否可达(是否能够被回收)
根搜索算法的基本思路就是经过一系列名为”GC Roots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证实此对象是不可用的。在Java语言中,能够做为GCRoots的对象包括下面几种:
2一、引用计数法
给对象中添加一个引用计数器,每当有一个地方引用它时计数器值就加1,当引用失效时计数器值就减1;任什么时候刻计数器都为0的对象就是再也不被使用的,垃圾收集器将回收该对象使用的内存。
优势:引用计数收集器能够很快的执行,交织在程序运行中。对程序须要不被长时间打断的实时环境比较有利。
缺点:
2二、复制算法
S0和s1将可用内存按容量分红大小相等的两块,每次只使用其中一块,当这块内存使用完了,就将还存活的对象复制到另外一块内存上去,而后把使用过的内存空间一次清理掉。这样使得每次都是对其中一块内存进行回收,内存分配时不用考虑内存碎片等复杂状况,只须要移动堆顶指针,按顺序分配内存便可,实现简单,运行高效。复制算法的缺点显而易见,可以使用的内存降为原来一半。复制算法用于在新生代垃圾回收
2三、标记-清除算法
标记-清除(Mark-Sweep)算法顾名思义,主要就是两个动做,一个是标记,另外一个就是清除。标记就是根据特定的算法(如:引用计数算法,可达性分析算法等)标出内存中哪些对象能够回收,哪些对象还要继续用。标记指示回收,那就直接收掉;标记指示对象还能用,那就原地不动留下。缺点是 标记与清除没有连续性效率低,清除以后内存会产生大量碎片;2四、标记-压缩算法
标记压缩法在标记清除基础之上作了优化,把存活的对象压缩到内存一端,然后进行垃圾清理。老年代使用的就是标记压缩法
2五、Minor GC和Full GC区别
新生代GC(Minor GC):指发生在新生代的垃圾收集动做,由于 Java 对象大多都具备朝生夕灭的特性,因此Minor GC 很是频繁,通常回收速度也比较快。当年轻代满时就会触发Minor GC,这里的年轻代满指的是Eden代满,Survivor满不会引起GCFull GC触发机制。
老年代GC(Major GC / Full GC):指发生在老年代的GC,出现了Major GC常常会伴随至少一次的 Minor GC。MajorGC 的速度通常会比 Minor GC 慢 10倍以上。当年老代满时会引起Full GC,Full GC将会同时回收年轻代、老年代,当永久代满时也会引起Full GC,会致使Class、Method元信息的卸载。
虚拟机给每一个对象定义了一个对象年龄(Age)计数器。若是对象在 Eden 出生并通过第一次 Minor GC 后仍然存活,而且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为 1。对象在 Survivor 区中每熬过一次 Minor GC,年龄就增长 1 岁,当它的年龄增长到必定程度(默认为 15 岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,能够经过参数 -XX:MaxTenuringThreshold (阈值)来设置。
2六、JVM的永久代中会发生垃圾回收么
垃圾回收会发生在永久代,若是永久代满了或者是超过了临界值,会触发彻底垃圾回收(Full GC)。
2七、元空间
元空间的本质和永久代相似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。所以默认状况下,元空间的大小仅受本地内存限制,但能够经过如下参数来指定元空间的大小。
除了上面两个指定大小的选项之外,还有两个与 GC 相关的属性:
2八、分代算法
这种算法根据对象的存活周期的不一样将内存划分红几块,新生代和老年代,这样就能够根据各个年代的特色采用最适当的收集算法。新建立的对象被分配在新生代,若是对象通过几回回收后仍然存活,那么就把这个对象划分到老年代。在新生代,每次垃圾收集器都发现有大批对象死去,只有少许存活,采用复制算法,只须要付出少许存活对象的复制成本就能够完成收集。老年代中由于对象存活率高、没有额外空间对它进行分配担保,就必须“标记-清除-压缩”算法进行回收。
2九、为何老年代使用标记压缩、新生代使用复制算法
当前商业虚拟机的垃圾收集都采用“分代收集”(Generational Collection)算法,这种算法只是根据对象存活周期的不一样将内存划分为几块。通常是把java堆分为新生代和老年代,这样就能够根据各个年代的特色采用最适合的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少许存活,那就选用复制算法,只须要付出少许存活对象的复制成本就能够完成收集。而老年代中由于对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记--清理”或者“标记--整理”算法来进行回收。
30、垃圾回收时的停顿现象
垃圾回收的任务是识别和回收垃圾对象进行内存清理,为了让垃圾回收器能够更高效的执行,大部分状况下,会要求系统进行一个停顿的状态。停顿的目的是为了终止全部的应用线程,只有这样的系统才不会有新垃圾的产生。同时停顿保证了系统状态在某一个瞬间的一致性,也有利于更好的标记垃圾对象。所以在垃圾回收时,都会产生应用程序的停顿
3一、什么是Java垃圾回收器
若是说收集算法是内存回收的方法论,那么垃圾收集器则是内存回收的具体实现,Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation)、自动回收(Garbage Collect)功能,这两个操做都发生在Java堆上(一段内存快)。某一个时刻一个对象若是有一个以上的引用(Rreference)指向它,那么该对象就为活着的(Live)不然死亡(Dead)视为垃圾,可被垃圾回收器回收再利用。垃圾回收操做须要消耗CPU、线程、时间等资源,因此容易理解的是垃圾回收操做不是实时的发生(对象死亡立刻释放),当内存消耗完或者是达到某一个指标(Threshold,使用内存占总内存的比列,好比0.75)时,触发垃圾回收操做。有一个对象死亡的例外,java.lang.Thread类型的对象即便没有引用,只要线程还在运行,就不会被回收。3二、Java堆溢出
错误缘由: java.lang.OutOfMemoryError: Java heap space 堆内存溢出
解决办法:设置堆内存大小 // -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
package com.zhang.test; import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) { List<Object> listObject = new ArrayList<Object>(); for (int i = 0; i < 10; i++) { System.out.println("i:" + i); Byte[] bytes = new Byte[100 * 1024 * 1024];//每次分配100M listObject.add(bytes); } System.out.println("添加成功..."); } }
3三、虚拟机栈溢出
错误缘由: java.lang.StackOverflowError 栈内存溢出
栈溢出产生于递归调用,循环遍历是不会的
解决办法:设置线程最大调用深度-Xss5m 设置最大调用深度
package com.zhang.test; public class JvmDemo04 { private static int count; public static void count() { try { count++; count(); } catch (Throwable e) { System.out.println("最大深度:" + count); e.printStackTrace(); } } public static void main(String[] args) { count(); } }
3四、串行回收器(Serial Collector)
单线程执行回收操做,回收期间暂停全部应用线程的执行,client模式下的默认回收器,经过-XX:+UseSerialGC命令行可选项强制指定。
新生代的回收算法(Minor Collection):复制算法
老年代的回收算法(Full Collection):标记-压缩算法
3五、并行回收器(ParNew回收器)
并行回收器在串行回收器基础上作了改进,他可使用多个线程同时进行垃圾回收,对于计算能力强的计算机而言,能够有效的缩短垃圾回收的时间。ParNew回收器是一个工做在新生代的垃圾收集器,回收策略和算法和串行回收器同样。ParNew回收器工做时的线程数量可使用XX:ParaleiGCThreads参数指定,通常最好和计算机的CPU至关,避免过多的线程影响性能。新生代并行,老年代串行;新生代复制算法、老年代标记-压缩
a:并行(Parallel):指多条垃圾收集线程并行工做,但此时用户线程仍然处于等待状态。
b:并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不必定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行在另外一个CPU上。
并发是一我的同时吃三个馒头,而并行是三我的同时吃三个馒头。
3六、并行回收集器(ParallelGC)
老年代ParallelOldGC回收器也是一种多线程的回收器和新生代的ParallelGC回收器同样,也是一种关注吞吐量的回收器,他使用了标记-压缩算法进行实现,-XX:+UseParallelOldGC 进行设置 XX:+ParallelCThread也能够设置垃圾收集时的线程教量。
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。能够同时并行多个垃圾收集线程,但此时用户线程必须中止。
-XX:+UseParNewGC:设置年轻代为多线程收集。可与CMS收集同时使用。在serial基础上实现的多线程收集器。
3七、CMS收集器(Concurrent Mark Sweep)
是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的java应用集中在互联网站或者B/S系统的服务端上,这类应用尤为重视服务的响应速度,但愿系统停顿时间最短,以给用户带来较好的体验。CMS收集器就很是符合这类应用的需求。
CMS收集器是基于“标记--清除”算法实现的, 他的运做过程相对于前几种收集器来讲更复杂一些,整个过程分为4个步骤:
3八、G1回收器
G1回收器(Garbage-First)是在]dk1.7中提出的垃圾回收器,从长期目标来看是为了取代CMS回收器,G1回收器拥有独特的垃圾回收策略,G1属于分代垃圾回收器,区分新生代和老年代,依然有eden和from/to区,它并不要求整个eden区或者新生代、老年代的空间都连续,它使用了分区算法。
G1收集器(Garbage-First):是当今收集器技术发展的最前沿的成果之一,G1是一款面向服务器端应用的垃圾收集器。与其余GC收集器相比,G1具有以下特色:
使用G1收集器时,java堆的内存布局就与其余收集器有很大差异,它将整个java堆划分为多个大小相等的独立区域(Region),虽然还保留新生代与老年代的概念,但新生代与老年代再也不试物理隔离的了,他们都是一部分Region(不须要连续)的集合。若是不计算维护Remembered Set的操做,G1收集器的运做大体可划分为一下几个步骤:
3九、GC日志
经过如下两段典型的GC日志进行分析:
33.125:[GC [DefNew:3324K->152K(3712K),0.0025925secs] 3324K->152K(11904K),0.0031680 secs] 100.667:[Full GC [Tenured:0K->210K(10240K),0.0149142secs] 4603K->210K(19456K),[Perm:2999K->2999K(21248K)],0.0150007 secs] <br>[Times:user=0.01 sys=0.00,real=0.02 secs]
最前面的数字“33.125:”和“100.667:”表明了GC发生的时间,这个数字的含义是从Java虚拟机启动以来通过的秒数。
GC日志开头的“[GC”和“[Full GC”说明了此次垃圾收集的停顿类型,而不是用来区分新生代GC仍是老年代GC的。若是有“Full”,说明此次GC是发生了Stop-The-World的,例以下面这段新生代收集器ParNew的日志也会出现“[Full GC”(这通常是由于出现了分配担保失败之类的问题,因此才致使STW)。若是是调用System.gc()方法所触发的收集,那么在这里将显示“[Full GC(System)”。
[Full GC 283.736:[ParNew:261599K->261599K(261952K),0.0000288 secs]
接下来的“[DefNew”、“[Tenured”、“[Perm”表示GC发生的区域,这里显示的区域名称与使用的GC收集是密切相关的,例如上面样例所使用的Serial收集器中的新生代名为“Default New Generation”,因此显示的是“[DefNew”。若是是ParNew收集器,新生代名称就会变为“[ParNew”,意为“Parallel New Generation”。若是采用Parallel Scavenge收集器,那它配套的新生代称为“PSYoungGen”,老年代和永久代同理,名称也是由收集器决定的。GC发生区域日志与GC收集器对照列表以下:
GC日志区域名 |
对应GC收集器名 |
[DefNew (Default New Generation) |
Serial收集器 |
[ParNew (Parallel New Generation) |
ParNew收集器 |
[PSYoungGen |
Parallel Scavenge收集器 |
[ParOldGen |
Parallel Old收集器 |
后面方括号内部的“3324K->152K(3712K)”含义是“GC前该内存区域已使用容量->GC后该内存区域已使用容量(该内存区域总容量)”。 而在方括号以外的“3324K->152K(11904K)”表示“GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)"。再日后,“0.0025925 secs”表示该内存区域GC所占用的时间,单位是秒。有的收集器会给出更具体的时间数据,如“[Times:user=0.01 sys=0.00,real=0.02 secs]”,这里面的user、sys和real与Linux的time命令所输出的时间含义一致,分别表明用户态消耗的CPU时间、内核态消耗的CPU事件和操做从开始到结束所通过的墙钟时间(Wall Clock Time)。
CPU时间与墙钟时间的区别是,墙钟时间包括各类非运算的等待耗时,例如等待磁盘I/O、等待线程阻塞,而CPU时间不包括这些耗时,但当系统有多CPU或者多核的话,多线程操做会叠加这些CPU时间,因此读者看到user或sys时间超过real时间是彻底正常的。
40、GC收集器参数
一、 Serial串行收集器相关的参数
-XX:+UseSerialGC | 虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收 |
-XX:SurvivorRatio | 新生代中设置eden区大小和survivior区大小的比例。默认为8,表明Eden:Survivor =8:1 |
-XX:PretenureSizeThreshold | 设置大对象直接进入老年代的阈值。当对象的大小超过这个值时,将直接在老年代分配。 |
-XX:MaxTenuringThreshold | 晋升到老年代的对象年龄。每一个对象在坚持过一次Minor GC以后,年龄增长1,当超过这个参数值时就进入老年代 |
注意:当GC发生在新生代时,称为Minor GC次收集;当GC发生在年老代时,称为Major GC主收集。 通常的Minor GC的发生频率要比Major GC高不少。
二、 ParNew并行收集器相关的参数
-XX:+UseParNewGC | 打开此开关后,使用ParNew + Serial Old的收集器组合进行内存回收 |
-XX:+UseParallelGC |
虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old(PS Mark Sweep)的收集器组合进行内存回收 |
-XX:+UseParallelOldGC | 打开此开关后,使用Parallel Scavenge + Parallel Old的收集器组合进行内存回收 |
-XX:ParallelGCThreads | 设置用于垃圾回收的线程数。一般状况下能够和CPU数量相等,但在CPU数量比较多的状况下,设置相·对较小的数值也是合理的。 |
-XX:MaxGCPauseMills | 设置最大垃圾收集停顿时间。它的值是一个大于0的正数。收集器在工做时,会调整java堆大小或者其余一些参数,尽量地把停顿时间控制在MaxGCPauseMills之内。 仅在Parallel Scavenge收集器时生效 |
-XX:GCTimeRatio | 设置吞吐量大小,即GC时间占总时间的比率。它的值是一个0到100之间的整数。假设GCTimeRatio的值为n,那么系统将花费不超过1/(1+n)的时间用于垃圾收集。默认值为99,即容许1%的GC时间,仅在Parallel Scavenge收集器时生效 |
-XX:+UseAdaptiveSizePolicy | 打开自适应GC策略。在这种模式下,新生代的大小、eden和survivior的比例、晋升老年代的对象年龄等参数会被自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点。 |
-XX:HandlePromotionFailure | 是否容许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的全部对象都存活的极端状况 |
三、 CMS 收集器相关的参数
-XX:+UseConcMarkSweepGC | 打开此开关后,使用ParNew + CMS —— Serial Old的收集器组合进行内存回收。Serial Old收集器是CMS收集器出现Concurrent Mode Failure失败后的备用收集器 |
-XX:ParallelCMSThreads | 设定CMS的线程数量。 |
-XX:CMSInitiatingOccupancyFraction | 设置CMS收集器在老年代空间被使用多少后触发,默认为68%。仅在CMS收集器时生效 |
-XX:+UseCMSCompactAtFullCollection | 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理。 仅在CMS收集器时生效 |
-XX:CMSFullGCsBeforeCompaction | 设定进行多少次CMS垃圾回收后,进行一次内存压缩(碎片整理)。 仅在CMS收集器时生效 |
-XX:+CMSClassUnloadingEnabled | 容许对类元数据区进行回收。 |
-XX:CMSInitiatingPermOccupancyFraction | 当永久区占用率达到这一百分比时,启动CMS回收(前提是-XX:+CMSClassUnloadingEnabled激活了)。 |
-XX:CMSInitiatingPermOccupancyOnly | 表示只在到达阈值的时候才进行CMS回收。 |
-XX:+CMSIncrementalMode | 使用增量模式,比较适合单CPU。增量模式在JDK8中标记为废弃,而且将在JDK9中完全移除。 |
四、 G1收集器相关的参数
-XX:+UseG1GC |
使用G1回收器。 |
-XX:MaxGCPauseMillis |
设置最大垃圾收集停顿时间。 |
-XX:GCPauseIntervalMillis |
设置停顿间隔时间。 |
https://blog.csdn.net/yjl33/article/details/78890363