【虚拟机参数】
在虚拟机运行的过程中,如果可以跟踪系统的运行状态,那么对于问题的排查会有一定会的帮助,为此,虚拟机提供了一些跟踪系统状态的参数,使用给定的参数执行Java虚拟机,就可以在系统运行时打应相关的日志,用于分析实际问题。我们可以进行虚拟机的参数配置,主要围绕着堆、栈、方法区进行配置。
【堆分配参数】
-XX:+PrintGC 使用这个参数,虚拟机启动后,只要遇到GC就会打印日志 -XX:+UseSerialGC 配置串行回收器 -XX:+PrintGCDetails 可以查看详细信息,包括各个区的情况 -Xms: 设置Java程序启动时初始堆的大小 -Xmx: 设置Java程序能获得的最大堆大小 -Xmx20m -Xms5m -XX:+PrintCommandLineFlags 可以将隐式或者显式给虚拟机参数输出
【配置参数入门实例】
package com.jvm.demo01; public class Demo01 { // -Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags public static void main(String[] args){ //查看GC信息 System.out.println("max memory:"+Runtime.getRuntime().maxMemory()); System.out.println("free memory:"+Runtime.getRuntime().freeMemory()); System.out.println("total memory:"+Runtime.getRuntime().totalMemory()); System.out.println("------------------------------"); byte[] b1 = new byte[1*1024*1024]; //分配了1M System.out.println("================分配了1M内存======================"); System.out.println("max memory:"+Runtime.getRuntime().maxMemory()); System.out.println("free memory:"+Runtime.getRuntime().freeMemory()); System.out.println("total memory:"+Runtime.getRuntime().totalMemory()); System.out.println("------------------------------"); byte[] b2 = new byte[4*1024*1024]; //又分配了4M System.out.println("================又分配了4M内存======================"); System.out.println("max memory:"+Runtime.getRuntime().maxMemory()); System.out.println("free memory:"+Runtime.getRuntime().freeMemory()); System.out.println("total memory:"+Runtime.getRuntime().totalMemory()); } }
【运行结果】
【注意】
在实际的工作中,可以直接将初始堆、最大堆的大小设置相等,这样的好处是减少程序运行时的垃圾回收次数,从而提高性能。
【新生代的配置】
-Xmn: 可以设置新生代的大小,设置一个比较大的新生代会减少老年代的大小,这个参数对系统性能以及GC行为由很大的影响,新生代大小一般会设置整个堆空间的1/3-1/4左右。 -XX:SurvivorRatio 用来设置新生代中的eden空间和from/to空间的比例。 含义:-XX:survivorRatio=eden/from=eden/to
【新生代配置实例】
package com.jvm.demo01; public class Demo02 { public static void main(String[] args){ //第一次配置 //-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC //初始化堆内存20M 最大堆内存大小20M 新生代大小1M eden/from=eden/t0=2 即eden512K from=to=256K //第二次配置 //-Xms20m -Xmx20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC //第三次配置 //-Xms20m -Xmx20m -XX:NewRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC //-XX:NewRatio=老年代/新生代 推荐新生代占整个对空间的1/3到1/4 所以一般-XX:NewRatio=2或者-XX:NewRatio=3 //一共向系统申请10M的空间,每次1M byte[] b =null; for(int i=0; i<10; i++){ b= new byte[1*1024*1024]; } } }
【第一次配置结果:-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC】
【第二次配置结果:-Xms20m -Xmx20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC】
【第三次配置:-Xms20m -Xmx20m -XX:NewRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC】(这里是老年代和新生代的比值=2)
【注意】
不同堆的分布情况,对系统执行会产生一定影响,在实际工作中,应该根据系统的特点做出合理的配置,基本策略:尽可能将对象预留在新生代,减少老年代的GC次数。
除了可以设置新生代的绝对大小(-Xmn),还可以使用(-XX:NewRatio)设置新生代和老年代的比例(-XX:NewRatio=老年代/新生代)
【堆溢出处理】
在Java程序运行过程中,如果堆空间不足,则会抛出内存溢出的错误OOM(Out Of Memory),一旦这类问题发生在生产环境,可能会引起严重的业务中断。
Java虚拟机提供了 -XX:+HeapDumpOnOutOfMemoryError,使用该参数可以在内存溢出时导出整个堆信息。
与之配合的还有参数 -XX:HeapDumpPath,设置导出堆的信息存放在本地的路径。
【堆内存溢出实例】
package com.jvm.demo01; import java.util.Vector; public class Demo3 { public static void main(String[] args) { //-Xms2m -Xmx2m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Demo03.dump //堆内存溢出保存的路径为 d:/Demo03.dump //堆内存溢出 Vector v = new Vector(); for(int i=0; i < 5; i ++){ v.add(new Byte[1*1024*1024]); } } }
【运行结果】
注意:生成的Demo03.dump可以使用专门的工具去使用。
【栈配置】
JAva虚拟机提供了参数 -Xss 来指定线程的最大空间,整个参数也直接决定了方法可以调用的最大深度。
【栈配置实例】
package com.jvm.demo01; public class Demo04 { //-Xss1m //-Xss5m //栈调用深度 private static int count; public static void recursion(){ count++; recursion(); } public static void main(String[] args){ try { recursion(); } catch (Throwable t) { System.out.println("调用最大深入:" + count); t.printStackTrace(); } } }
【-Xss1m的运行结果】
【-Xss5m的运行结果】
【方法区】
和Java堆一样,方法区是一块所有线程共享的内存区域,它用于保存系统的类信息,方法区(永久区)可以保存多少信息可以对其进行配置。
在默认情况下,-XX:MaxPermSize 为64m,如果系统运行时生产了大量的类,需要设置一个合适的方法区,以免出现永久去内存溢出的问题。
-XX:PermSize=64M -XX:MaxPermSize=64M
【直接内存配置】
直接内存配置也是Java程序中非常重要的组成部分,特别在NIO中,直接内存跳过了Java堆,使Java程序可以直接访问原生堆空间,因此在一定程度上也加快了内存空间的访问速度。
但是直接内存一定可以提高内存访问速度也不一定,需要具体情况具体分析。
相关配置参数 -XX:MaxDirectMemorySize
如果不设置 -XX:MaxDirectMemorySize,则其默认值为最大堆空间,即-Xmx,直接内存内存使用达到上限时,就会触发垃圾回收,如果不能有效地释放空间,也会引起系统的OOM。
【Client和Server虚拟机的工作模式】
目前Java虚拟机支持Client和Server两种模式,使用参数-client可以指定使用Client模式,使用-Server即使用Server模式。
可以直接在命令行查看当前系统自动选择的运行模式 java -version
[ 两者的区别 ]
Client模式相对Server模式启动较快,如果系统不追求系统的长时间使用性能,仅仅是测试,可以使用Client模式。
Server模式启动比较慢,原因是会对其进行复杂的系统信息收集和使用复杂算法对程序进行优化。
一般我们生产环境都会使用Server模式,长期运行其性能要远远快于Client模式。