JVM-性能调优

内存溢出

内存溢出的原因:程序在申请内存时,没有足够的内存空间。

内存溢出的几种方式:
1.栈溢出:方法死循环递归调用(StackOverflowError)、不断建立线程(OurOfMemoryError)
2.堆溢出:不断创建对象,分配对象大于最大堆的大小(OurOfMemoryError)
3.直接内存:分配的本地内存大小大于JVM的限制
4.方法区溢出:在经常动态生产大量Class的应用中,CGLib字节码增强,动态语言,大量JSP,基于OSGi的应用

内存泄漏

程序在申请内存后,无法释放已申请的内存空间

内存泄漏的几种方式:
1.长生命周期的对象持有短生命周期对象的引用:例如将ArrayList设置为静态常量,则容器中的对象在程序结束前是不能被释放,造成内存泄漏。
2.连接未关闭 : 数据库连接、网络链接和IO链接等
3.变量作用域不合理 : 1.一个变量定义的作用范围大于其适用范围。2,没有及时把对象设置为null
4.内部类持有外部类 :非静态内部类创建或持有外部类的引用,默认是强引用,因此,内部类的生命周期长于外部类,很容易内存泄漏
5.Hash值改变 : 集合中修改了对象中的那些参与计算哈希值的字段,会导致无法从集合中单独删除当前对象,造成内存泄漏。

内存泄漏和内存溢出辨析

相同与不同
内存溢出:实实在在的内存空间不足导致
内存泄漏:该释放的对象没有释放,多见于自己使用容器保存原的情况下。

如何避免
内存溢出:检查代码以及设置足够的空间
内存泄漏:一定代码有问题

往往很多情况下,内存溢出就是内存泄漏造成的。

GC调优原则

  1. 大多数的java应用不需要GC调优
  2. 大部分需要GC调优的,不是参数问题,而是代码问题
  3. 在实际项目中,分析GC情况优化代码比调整GC参数要重要
  4. GC调优是最后的手段

目的

  1. GC的时间足够小
  2. GC的次数足够小

调优步骤

  1. 监视GC的状态
  2. 分析结果,判断是否需要优化
  3. 调整GC类型和内存分配
  4. 不断分析和调整
  5. 全面应用参数

逃逸分析

栈上分配
-XX:+DoEscapeAnalysis:启用逃逸分析(默认打开)
-XX:+EliminateAllocations:标量替换(默认打开)
-XX:+UseTLAB 本地线程分配缓冲(默认打开)

如果是逃逸分析出来的对象可以在栈上分配,就不用垃圾回收
没有逃逸分析的对象都在堆上分配(触发频繁GC,加重负担)
在这里插入图片描述

JVM调优指令

1. jps

jps是jdk提供的一个查看当前java进程的小工具

jps [option] [hostid]
option参数可输也可不输。

-l: 输出主类全名或jar路径
-q: 只输出LVMID
-m: 输出JVM启动时传递给main()的参数
-v: 输出JVM启动时显示指定的JVM参数

在这里插入图片描述

2. jstat

jstat的主要作用就是对Java应用程序的资源和性能进行实时监控的命令行工具,主要包括GC情况和Heap Size资源 使用情况。

jstat [option] vmid [interval] [count]

option: 操作参数
vmid: 本地虚拟机进程ID
interval: 连续输出的时间间隔
count: 连续输出的次数

在这里插入图片描述
下面是对一些常用的option参数的解释,注意1797是通过jps -l指令执行过程中得到的id,即我本地运行的Tomcat的id

-compiler 编译统计

jstat -compiler 1797
在这里插入图片描述

Compiled : 编译数量
Failed : 编译失败数量
Invalid : 无效数量
Time : 编译耗时
FailedType : 失败类型
FailedMethod : 失败方法的全限定名
-class 类加载统计

jstat -class 1797
在这里插入图片描述

Loaded : 加载class的数量
Bytes : class字节大小
Unloaded : 未加载class的数量
Bytes : 未加载class的字节大小
Time : 加载时间
-gc 垃圾回收统计

jstat -gc 1797
在这里插入图片描述

S0C : survivor0区的总容量
S1C : survivor1区的总容量
S0U : survivor0区已使用的容量
S1U : survivor1区已使用的容量
EC : Eden区的总容量
EU : Eden区已使用的容量
OC : Old区的总容量
OU : Old区已使用的容量
PC : 当前perm的容量 (KB)
PU : perm的使用 (KB)
YGC : 新生代垃圾回收次数
YGCT : 新生代垃圾回收时间
FGC : 老年代垃圾回收次数
FGCT : 老年代垃圾回收时间
GCT : 垃圾回收总消耗时间

jstat -gc 1797 5000
5秒打印一次
在这里插入图片描述

-gcutil 总结垃圾回收统计

jstat -gcutil 1797
在这里插入图片描述

S0 : survivor0区的总容量
S1 : survivor1区的总容量
E : Eden区的总容量
O : Old区的总容量
OU : Old区已使用的容量
YGC : 新生代垃圾回收次数
YGCT : 新生代垃圾回收时间
FGC : 老年代垃圾回收次数
FGCT : 老年代垃圾回收时间
GCT : 垃圾回收总消耗时间
-gccause gc原因调查

jstat -gccause 1797
在这里插入图片描述

LGCC:最近垃圾回收的原因
GCC:当前垃圾回收的原因
-gccapacity 堆内存统计

jstat -gccapacity 1797
在这里插入图片描述

NGCMN : 新生代占用的最小空间
NGCMX : 新生代占用的最大空间
OGCMN : 老年代占用的最小空间
OGCMX : 老年代占用的最大空间
OGC:当前年老代的容量 (KB)
OC:当前年老代的空间 (KB)
PGCMN : perm占用的最小空间
PGCMX : perm占用的最大空间

3. jmap 生成虚拟机的内存转储快照(heapdump)文件

jmap [option] vmid

jmap(JVM Memory Map)命令用于生成heap dump文件,如果不使用这个命令,还可以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM时自动生成dump文件。jmap不仅能生成dump文件,还能查询finalize执行队列、Java堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。

dump : 生成堆转储快照
finalizerinfo : 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
heap : 显示Java堆详细信息
histo : 显示堆中对象的统计信息
permstat : to print permanent generation statistics
F :-dump没有响应时,强制生成dump快照
Attaching to process ID 94358, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.79-b02

using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration: //堆内存初始化配置
   MinHeapFreeRatio = 0 //jvm参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
   MaxHeapFreeRatio = 100 //jvm参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
   MaxHeapSize      = 1073741824 (1024.0MB) //jvm参数-XX:MaxHeapSize=设置JVM堆的最大大小
   NewSize          = 536870912 (512.0MB)//jvm参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
   MaxNewSize       = 536870912 (512.0MB)//jvm参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
   OldSize          = 5439488 (5.1875MB) //参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小
   NewRatio         = 2 //参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
   SurvivorRatio    = 8 //参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值
   PermSize         = 536870912 (512.0MB) //参数-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小
   MaxPermSize      = 1073741824 (1024.0MB)//参数-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage: //堆内存使用情况
PS Young Generation
Eden Space:
   capacity = 300417024 (286.5MB) //总容量
   used     = 231151904 (220.44363403320312MB) //已使用
   free     = 69265120 (66.05636596679688MB)//剩余容量
   76.94367680041994% used //Eden区使用比率
From Space: // S0 内存使用情况
   capacity = 120586240 (115.0MB)
   used     = 53528904 (51.04914093017578MB)
   free     = 67057336 (63.95085906982422MB)
   44.39055733058763% used
To Space:  // S1 内存使用情况
   capacity = 115867648 (110.5MB)
   used     = 0 (0.0MB)
   free     = 115867648 (110.5MB)
   0.0% used
PS Old Generation // Old区使用情况
   capacity = 536870912 (512.0MB)
   used     = 241598968 (230.40673065185547MB)
   free     = 295271944 (281.59326934814453MB)
   45.00131458044052% used
PS Perm Generation // 永久代使用情况
   capacity = 536870912 (512.0MB)
   used     = 143245904 (136.6099395751953MB)
   free     = 393625008 (375.3900604248047MB)
   26.681628823280334% used

18942 interned Strings occupying 2284376 bytes.

也可以使用dump参数,将dump文件保存到本地,然后再通过工具来分析。

-dump::live,format=b,file=<filename> pid
$ ./jmap -dump:live,format=b,file=/tmp/myDump.hprof 94358
Dumping heap to /private/tmp/myDump.hprof ...
Heap dump file created

4. jstack 生成java虚拟机当前时刻的线程快照

jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。


[root@localhost bin]# jstack -help
Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)
 
Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

-F:当正常输出请求不被响应时,强制输出线程栈堆。
-l:除线程栈堆外,显示关于锁的附加信息。
-m:如果调用本地方法的话,可以显示c/c++的栈堆

[root@localhost bin]# jstack -m 1797 | more
Attaching to process ID 24971, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.79-b02
Deadlock Detection:
 
No deadlocks found.
 
----------------- 24972 -----------------
0x00007fe07d2cd69d  __GI___poll + 0x2d
0x00007fe070dc80a7  Java_java_net_PlainSocketImpl_socketAccept + 0x1e7
0x00007fe0745a3d98  * java.net.PlainSocketImpl.socketAccept(java.net.SocketImpl) bci:0 (Interpreted frame)
0x00007fe074597058  * java.net.AbstractPlainSocketImpl.accept(java.net.SocketImpl) bci:7 line:398 (Interpreted frame)
0x00007fe074597058  * java.net.ServerSocket.implAccept(java.net.Socket) bci:60 line:530 (Interpreted frame)
0x00007fe074597058  * java.net.ServerSocket.accept() bci:48 line:498 (Interpreted frame)
0x00007fe074597233  * org.apache.catalina.core.StandardServer.await() bci:180 line:470 (Interpreted frame)
0x00007fe074597706  * org.apache.catalina.startup.Catalina.await() bci:4 line:782 (Interpreted frame)
0x00007fe074597058  * org.apache.catalina.startup.Catalina.start() bci:209 line:728 (Interpreted frame)
0x00007fe0745914e7  <StubRoutines>
0x00007fe07c967e95  _ZN9JavaCalls11call_helperEP9JavaValueP12methodHandleP17JavaCallArgumentsP6Thread + 0x365
0x00007fe07c9668f8  _ZN9JavaCalls4callEP9JavaValue12methodHandleP17JavaCallArgumentsP6Thread + 0x28
0x00007fe07cbfdeef  _ZN10Reflection6invokeE19instanceKlassHandle12methodHandle6Handleb14objArrayHandle9BasicTypeS3_bP6Thread + 0x
47f
0x00007fe07cbfeca0  _ZN10Reflection13invoke_methodEP7oopDesc6Handle14objArrayHandleP6Thread + 0x160

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值