jvm笔记

来源:互联网 发布:mysql中if exists用法 编辑:程序博客网 时间:2024/04/29 09:58

一、jvm配置设置地方

1、tomcat::Linux 在TOMCAT_HOME/bin/catalina.sh 、Windows在catalina.bat ,修改JAVA_OPTS

2、eclipse:

      (2.1)为单独测试类配置jvm:在需要运行的测试用例上右键选择Run As => Run Configurations => 在打开的Run Configurations中找到Junit(或者java application,取决怎样测试)一栏,在Junit一栏下找到自己的测试用例,如果没有则双击Junit=》打开Arguments Tab,在VM arguments一栏中输入需要设置的jvm参数=》点击Run即可.

       (2.2)为eclipse加载的jdk/jre配置jvm:该参数配置是全局的,运行用例时,不需要为每一个测试用例单独配置。
Eclipse中选择Window=>Preferences=>Java=>Installed JRES=>选中安装的jdk或者jre并进行编辑=》在Default VM Arguments中输入需要设置的jvm参数=》点击Finish完成设置.

二、参数配置说明

1.gc配置

-XX:+PrintGCDetails : 打印gc详细信息

-XX:+PrintGCTimeStamps :打印CG发生的时间戳
-Xloggc:log/gc.log :指定GC log
的位置,以文件输出

收集器设置

-XX:+UseSerialGC:设置串行收集器

-XX:+UseParallelGC:设置并行收集器

-XX:+UseParalledlOldGC:设置并行年老代收集器

-XX:+UseConcMarkSweepGC:设置并发收集器

并行收集器:

-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。

-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间

-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

并发收集器设置 :

-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。

-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。


2.堆参数配置

-Xmx –Xms :指定最大堆和最小堆,为减少系统开销一般设置一样(如:-Xmx20m -Xms20m)
-Xmn :设置新生代大小(如:–Xmn7m)
-XX:NewRatio=n :新生代(eden+2*s)和老年代(不包含永久区)的比值(如:4表示新生代:老年代=1:4,即年轻代占堆的1/5)
-XX:SurvivorRatio=n :设置两个幸存区和eden的比(如:8表示两个Survivor:eden=2:8,即一个Survivor占年轻代的1/10)

-XX:+HeapDumpOnOutOfMemoryError :OOM内存溢出时导出堆信息到文件

-XX:+HeapDumpPath :导出OOM的路径

-XX:OnOutOfMemoryError :在OOM时,执行一个脚本(可以发送邮件,甚至是重启程序等)

备注:官方推荐新生代占堆的3/8,幸存代占新生代的1/10;记得配置OOM时导出堆信息,便于排查问题

3.永久区参数配置

-XX:PermSize=n-XX:MaxPermSize=n :设置永久区的初始空间和最大空间

4.栈配置

-Xss :常只有几百K(如:-Xss128K)

三、jvm内存分配

jvm内存分为PC计数器/堆/栈(jvm栈,本地方法栈)/方法区.


PC计数器:它保存的是程序当前执行的指令的地址以及得到下一条指令的地址

堆:是用来存储对象本身的以及数组,堆是被所有线程共享的,在JVM中只有一个堆(new出来的对象)

堆分为New(年轻代)和Tenured(年老代)。

年轻代:年轻代用来存放JVM刚分配的Java对象

年老代:年轻代中经过垃圾回收没有回收掉的对象将被Copy到年老代

其中年轻代又分为几个部分:

Eden:Eden用来存放JVM刚分配的对象

Survivor1

Survivro2:两个Survivor空间一样大,当Eden中的对象经过垃圾回收没有被回收掉时,会在两个Survivor之间来回Copy,当满足某个条件,比如Copy次数,就会被Copy到Tenured。显然,Survivor只是增加了对象在年轻代中的逗留时间,增加了被垃圾回收的可能性。

虚拟机栈:Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,是线程私有的。在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池的引用、方法返回地址(Return Address)和一些额外的附加信息。

局部变量表:就是用来存储方法中的局部变量(包括在方法中声明的非静态变量以及函数形参)。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。

操作数栈:对表达式求值,进行计算的过程

方法返回地址:当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址

本地方法栈:本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。

方法区:它与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式。很多人习惯将方法区称为“永久代”,是因为HotSpot虚拟机以永久代来实现方法区,自从JDK7之后,Hotspot虚拟机便将运行时常量池从永久代移除了。

四、调优

1、监控查看

(1) 命令行工具:

A. jps(JavaVirtual Machine Process Status Tool)

jps主要用来输出JVM中运行的进程状态信息.常用的参数为:
    -q:只输出LVMID,省略主类的名称
    -m:输出虚拟机进程启动时传给主类main()函数的参数
    -l:输出主类的全类名,如果进程执行的是Jar包,输出Jar路径
    -v:输出虚拟机进程启动时JVM参数
命令格式:jps [option] [hostid]

(如果不指定hostid就默认为当前主机或服务器)

B.jstack

jstack主要用来查看某个Java进程内的线程堆栈信息,可以定位线程出现长时间停顿的原因,常用的参数为:

   -F:当正常输出的请求不被响应时,强制输出线程堆栈
   -l:除堆栈外,显示关于锁的附加信息
   -m:如果调用到本地方法的话,可以显示C/C++的堆栈
命令格式:jstack [option] vmid

jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。

第一步:先找出Java进程ID,我部署在服务器上的Java应用名称为mrf-center:

root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep

root 21711 1 1 14:47 pts/3 00:02:10 java -jar mrf-center.jar

第二步:找出该进程内最耗费CPU的线程,TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为21742的线程

root@ubuntu:/#top -Hp 21711


第三步:得到21742的十六进制值为54ee,后面会用到

root@ubuntu:/# printf "%x\n" 21742

第四步:用jstack来输出进程21711的堆栈信息,然后根据线程ID的十六进制值grep

root@ubuntu:/# jstack 21711 | grep 54ee

"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait()

可以看到CPU消耗在PollIntervalRetrySchedulerThread这个类的Object.wait(),这样可以定位到相关代码

C.jstat

jstat可以实时显示JVM进程中类装载、内存、垃圾收集、JIT编译等数据。如果在服务启动时没有指定启动参数-verbose:gc,则可以用jstat实时查看gc情况。

jstat有如下选项:
   -class:监视类装载、卸载数量、总空间及类装载所耗费的时间
   -gc:监听Java堆状况,包括Eden区、两个Survivor区、老年代、永久代等的容量,以用空间、GC时间合计等信息
   -gccapacity:监视内容与-gc基本相同,但输出主要关注java堆各个区域使用到的最大和最小空间
   -gcutil:监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
   -gccause:与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
   -gcnew:监视新生代GC状况
   -gcnewcapacity:监视内同与-gcnew基本相同,输出主要关注使用到的最大和最小空间
   -gcold:监视老年代GC情况
   -gcoldcapacity:监视内同与-gcold基本相同,输出主要关注使用到的最大和最小空间
   -gcpermcapacity:输出永久代使用到最大和最小空间
   -compiler:输出JIT编译器编译过的方法、耗时等信息
   -printcompilation:输出已经被JIT编译的方法

命令格式:jstat [option vmid [interval[s|ms] [count]]]

如果省略interval和count,则只查询一次

例如:jstat -gc 309 1000 5代表着:搜集vid为309的java进程的整体gc状态, 每1000ms收集一次,共收集5次;XXXC表示该区容量,XXXU表示该区使用量,各列解释如下:
S0C:新生代中Survivor space S0区容量(S1区相同,略)
S0U:新生代中Survivor space S0区已使用
EC:新生代中Eden区容量
EU:新生代中Eden区已使用
OC:老年代容量
OU:老年代已使用
PC:Perm容量
PU:Perm区已使用
YGC:Young GC(Minor GC)次数
YGCT:Young GC总耗时
FGC:Full GC次数
FGCT:Full GC总耗时
GCT:GC总耗时

D.jmap命令(Java Memory Map)

用于显示当前Java堆和永久代的详细信息(如当前使用的收集器,当前的空间使用率等)
   -dump:生成java堆转储快照
   -heap:显示java堆详细信息(只在Linux/Solaris下有效)
   -F:当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照(只在Linux/Solaris下有效)
   -finalizerinfo:显示在F-Queue中等待Finalizer线程执行finalize方法的对象(只在Linux/Solaris下有效)
   -histo:显示堆中对象统计信息
   -permstat:以ClassLoader为统计口径显示永久代内存状态(只在Linux/Solaris下有效)
 命令格式:jmap [option] vmid
其中前面3个参数最重要,如:
查看对详细信息:jmap -heap 309
生成dump文件: jmap -dump:file=./test.prof 309,可以配合MAT 内存分析工具(Memory Analysis Tool)或者jhat使用

E.jinfo

用于查询当前运行这的JVM属性和参数的值。
jinfo可以使用如下选项:
   -flag:显示未被显示指定的参数的系统默认值
   -flag [+|-]name或-flag name=value: 修改部分参数
   -sysprops:打印虚拟机进程的System.getProperties()
 命令格式:jinfo [option] pid

如:显示是否打印GC详细信息

jinfo -flag PrintGCDetails 2972

(2)图形工具

A.JConsole

注:如果连接不上可以加入下面jvm参数

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8012
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

B.VisualVM

http://www.cnblogs.com/wade-xu/p/4369094.html

C.MAT



2、调优分析

判断是否需要优化:

如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化;如果GC时间超过1-3秒,或者频繁GC,则必须优化;

注:如果满足下面的指标,则一般不需要进行GC:

   Minor GC执行时间不到50ms;

   Minor GC执行不频繁,约10秒一次;

   Full GC执行时间不到1s;

   Full GC执行频率不算频繁,不低于10分钟1次;

调优原则:

    多数的Java应用不需要在服务器上进行GC优化;
    多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题;
    在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合);
    减少创建对象的数量;
    减少使用全局变量和大对象;
    GC优化是到最后不得已才采用的手段;
    在实际使用中,分析GC情况优化代码比优化GC参数要多得多;

GC优化的目的有两个:

    将转移到老年代的对象数量降低到最小;
    减少full GC的执行时间;

优化手段:
    减少使用全局变量和大对象;
    调整新生代的大小到最合适;
    设置老年代的大小为最合适;
    选择合适的GC收集器;

(通过不断的试验和试错,分析并找到最合适的参数)



查阅资料:

http://uule.iteye.com/blog/2114697

http://www.cnblogs.com/dolphin0520/p/3613043.html

调优工具:http://blog.csdn.net/fenglibing/article/details/6411999

0 0
原创粉丝点击