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
- 这个值默认是跟堆内存的最大值一样的
最后,我自己是一名从事了多年开发的JAVA老程序员,辞职目前在做自己的java私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的java学习干货,可以送给每一位喜欢java的小伙伴,想要获取的可以关注我的头条号并在后台私信我:java,即可免费获取。
————————————————————
作者:cenzhipeng