jvm系列笔记-命令行参数

java命令行

执行java程序

两种用法:

  • 一种是使用-cp参数,然后传入一大堆jar包,接着传入主类,最后传入程序参数。例如:
    • java -Dkey1=val1 -Dkey2=val2 -cp a.jar:b.jar:c.jar aaa.bbb.ccc.Main arg1 arg2 arg3
    • 上述的方式中,-D参数定义的是系统属性,在java中可以通过System.getProperty(key1)的方式读取,arg1 arg2 arg3定义的是程序参数,最后也就是main函数的args数组参数。
  • 第二种是使用-jar参数,然后传入一个jar包,接着就是程序参数。例如:
    • java -Dkey1=val1 -Dkey2=val2 -jar xxx.jar arg1 arg2 arg3
    • 这种方式只能使用一个jar包,并且jar包需要META_INF目录下的manifest.MF文件中定义了Main-Class,会自动去启动这个main类

顺便说一句,System.getEnv()获取的是环境变量,就是通常意义上的进程的环境变量(jvm实质就是个进程),System.getProperty(key1)获取的是系统属性,这个是java自己定义的一种参数,arg1 arg2是程序参数,这个对应于main函数接收的参数。

虚拟机参数

运行模式、栈空间大小、栈帧的结构

-client -server

  • 表示虚拟机的运行模式,server模式的启动慢,但是总体运行的性能比client高,优化更多(所以热身时间长)

-Xss1024k

  • 表示线程的栈空间大小是1024k,线程的栈深度实际上是没有限制的(可能有别的限制我不知道),之所以出现StackOverflow的异常,是因为栈空间的大小达到了限制。
  • 线程栈的每个元素都是栈帧,栈帧的大小不是固定的(每个方法调用对应一个栈帧)。所以如果栈帧大,那么栈的深度就会小,栈帧小,栈的深度就会大(因为 栈空间 = 栈帧大小 * 栈深)。
  • 栈帧可以理解成一段内存,栈帧本身并不是栈式的结构,是可以在栈帧中进行随机访问的读写的。
  • 栈帧至少包含有局部变量表操作数栈帧数据区

栈帧的结构

局部变量表

就很简单,我们的方法的参数、方法里面声明的局部变量,都存在局部变量表里。局部变量中,会有一堆插槽,一个插槽可以放一个数据(一个byte、一个char、一个short...等,以及一个reference)。虚拟机通过插槽索引来使用局部变量表里的数据(比如说引用插槽0,可能对应一个数字3,引用插槽2,可能对应一个对象的引用)

操作数栈

操作数栈是栈帧里的一个栈(就是说,栈帧里有好几块不同的区域,其中一块区域作为一个栈来使用了,就是操作数栈)。主要是用来保存计算的中间结果,以及作为计算过程中变量的临时存储空间(因为一些指令操作的模式都是入栈出栈然后计算)。

帧数据区

栈帧除了上面的数据之外,还需要一些数据来支持常量池解析,方法返回和异常处理等。比如我们返回值存放在哪里,异常处理表存放在哪里,这些都需要放在帧数据区,jvm还可以实现一些别的数据区存放在这里。

栈上分配

这是个优化技术,基本思想是,对于不可能被其它线程访问到的对象,可以打散分配在栈上。比如我们在方法内创建的一个临时对象,接收对象引用的也是个局部变量,对象也没有传递给其它方法。那么这个对象就不会发生逃逸,就可能会被以栈的方式进行分配。(栈空间很小,所以只能分配小对象)好处是栈帧被回收的时候,对象直接就会被回收了。

元空间参数

-XX:MaxMetaspaceSize=10m

  • 表示jvm使用的元空间大小是10M
  • 元空间中存储的是类的信息,比如类的字段、方法、常量池等
  • 元空间所属的内存是堆外内存。如果不指定大小,java8中默认没有设置元空间上限,会在需要时增长直到耗尽系统内存。
  • 元空间越大,系统可以加载的类越多(因为加载的类的信息都在这里,所以一些需要动态代理的框架或程序对元空间会有一些消耗)

GC参数

-XX:+PrintGC

  • 打印GC信息,当遇到GC后,JVM就会打印出GC信息,如下图
  • 有了GC信息之后,我们就比较容易监控GC的用时和效果了

-XX:+PrintGCDetails

  • 打印详细GC信息,GC的信息更加详细和丰富。它会在JVM退出前,打印堆的详细信息。
  • PSYoungGen表示年轻代中的eden+from区
  • ParOldGen表示老年代
  • space 65536K, 2% used [0x000000076ab00000,0x000000076acb4e98,0x000000076eb00000) 三个数字表示内存的下界、当前上界、上界。

-XX:+PrintHeapAtGC

  • 每次在GC后,都打印堆的详细信息,这个就比上面的detail更加详细了。

-XX:+PrintGCTimeStamps

  • 每次打印GC日志的时候,还要输出时间信息(系统启动后的时间)。

-XX:+PrintGCApplicationConcurrentTime

  • 打印应用程序的执行时间(到达安全点safepoint的时间),一般是跟下面的参数一起使用

-XX:+PrintGCApplicationStoppedTime

  • 打印应用程序因为GC停顿的时间(stw机制)

-XX:+PrintReferenceGC

  • 打印引用相关的GC。这个可以跟踪系统内的软引用、弱引用、虚引用和Finallize队列。

-Xloggc:log/gc.log

  • 默认情况GC日志是直接在控制台中输出(标准输出),使用这个参数可以将其输出到我们指定的地方,这里是说当前目录的log目录下的gc.log文件中。

类信息参数

-verbose:class 或 -XX:+TraceClassLoading 与 -XX:+TraceClassUnloading

  • 这两类参数是等价的,都是跟踪类的加载和卸载
  • -verbose:class 跟踪类的加载和卸载
  • -XX:+TraceClassLoading 跟踪类的加载
  • -XX:+TraceClassUnloading 跟踪类的卸载

-XX:+PrintClassHistogram

  • 允许打印和查看系统中类的分布信息
  • 开启了这个参数后,在java的控制台中按下Ctrl + Break,控制台就会显示当前的类信息柱状图。如下显示了当前占用空间最多的类,实例个数、空间大小等

系统参数本身的相关参数

-XX:+PrintFlagsFinal

  • 打印所有系统参数

-XX:+PrintCommandLineFlags

  • 打印传递给虚拟机的显式和隐式参数,隐式参数未必是命令行给的,可能是虚拟机启动时自行设置的。

堆空间参数

-Xms10m -Xmx20m

  • 最小堆内存10m
  • 最大堆内存20m
  • 生产项目很多都是直接设置成一样大的,直接全都设置成最大的内存。这样一开始就是使用的最大内存,减少GC次数提升性能,并且防止内存的复制(扩大内存的时候可能会发生)

-Xmn3m

  • 设置新生代大小是3m
  • 一般设置为整个堆空间大小的1/3到1/4

-XX:SurvivorRatio=2

  • 表示新生代中,eden/from(以及eden/to)的比值是2
  • 比如说新生代40m内存,那么eden区就是20m,from和to都是10m

-XX:NewRatio=3

  • 表示 老年代/新生代 的比值是3
  • 比如说一共堆内存是40m,那么新生代10m,老年代30m

堆溢出处理参数

-XX:+HeapDumpOnOutOfMemoryError

  • 在内存溢出时,导出整个堆的信息

-XX:HeapDumpPath=d:/a.dump

  • 内存溢出时,导出堆的信息到这个文件里。与上面的参数配合使用
  • 导出了dump文件后,可以使用MAT工具进行分析

-XX:OnOutOfMemoryError=d:/tools/printstack.bat

  • 内存溢出的时候,执行这个脚本
  • 一般用来报警、通知、存储Thread Dump或者 Core Dump文件来进行分析

直接内存参数

-XX:MaxDirectMemorySize=100m

  • 最大直接内存是100m
  • 这个值默认是跟堆内存的最大值一样的

猜你喜欢

转载自juejin.im/post/5d898610518825090f4199e1