JVM调优总结

简介: JVM调优总结

此篇文章用于查内存泄漏和FullGC

因为在Linux环境,用jdk自带的jmap工具(Linux/Unix环境特有的),可以对进程中的内存对象监视,然后就运行命令

jmap -histo [pid],找内存中的对象数目变化。

watch "jmap -histo 7220| grep u9"

查看有u9字段的对象数目和大小

查看

jvm中对象内存占用情况(jmap -histo pid | head -n8, 因为内容太多, 因此需要head一下)

导出整个JVM中的内存信息

通过以上方法能查看到JVM中对象内存的占用情况,但很多时候还要知道这个对象到底是谁创建的。例如上面显示出来的[C,只知道它占用了那么多的空间,但不知道是什么对象创建出的[C,于是jmap提供了导出整个jvm中的内存信息的支持。基于一些jvm内存的分析工具,例如sun JDK 6中的jhat、Eclipse Memory Analyzer,可以分析jvm中内存的详细信息,例如[C是哪些对象创建的。

----------------------------------------------------

执行如下命令即可导出整个jvm中的内存信息:

  1. jmap -dump:format=b,file=文件名 [pid]
  2. 在用jhat -J-Xmx1024M [file] 这里的file就是步骤1中的文件名,
  3. 执行后等待console中输出Started HTTP server on port 7000,看到后就可以通过浏览器访问http://ip:7000/了,此页面默认为按package分类显示系统中所有的对象实例。在页面的最下端有Other Queries导航,其中有显示jvm中对象实例个数的链接、有显示jvm中对象大小的链接等,点击显示jvm中对象大小的链接

-------------------------------------------------------

jmap -heap [pid] 在linux上执行改命令,就可查看整个JVM中各个代的内存状况

using thread-local object allocation.  

Parallel GC with 8 thread(s)

Heap Configuration:  

  MinHeapFreeRatio = 40

  MaxHeapFreeRatio = 70

  MaxHeapSize      = 1610612736 (1536.0MB)  

  NewSize          = 524288000 (500.0MB)  

  MaxNewSize       = 524288000 (500.0MB)  

  OldSize          = 4194304 (4.0MB)  

  NewRatio         = 8

  SurvivorRatio    = 8

  PermSize         = 100663296 (96.0MB)  

  MaxPermSize      = 268435456 (256.0MB)

Heap Usage:  

PS Young Generation  

Eden Space:  

  capacity = 430702592 (410.75MB)  

  used     = 324439936 (309.4100341796875MB)  

  free     = 106262656 (101.3399658203125MB)  

  75.32806675098904% used  

From Space:  

  capacity = 46333952 (44.1875MB)  

  used     = 13016424 (12.413429260253906MB)  

  free     = 33317528 (31.774070739746094MB)  

  28.092626331550566% used  

To Space:  

  capacity = 46792704 (44.625MB)  

  used     = 0 (0.0MB)  

  free     = 46792704 (44.625MB)  

  0.0% used

PS Old Generation  

  capacity = 1086324736 (1036.0MB)  

  used     = 945707880 (901.8973159790039MB)  

  free     = 140616856 (134.1026840209961MB)  

  87.05572548059884% used

PS Perm Generation  

  capacity = 100663296 (96.0MB)  

  used     = 46349592 (44.202415466308594MB)  

  free     = 54313704 (51.797584533691406MB)  

  46.044182777404785% used

如果PS Old Generation或者PS Perm Generation被填满,就会导致fullGC,进而导致CPU占用率大幅度提高

--------------------------------

并发回收 CMS收集器 UseConcMarkSweepGC

适用情况:“对响应时间有高要求”,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器、电信交换、集成开发环境。

并行回收                        UseParallelGC

--适用情况:“对吞吐量有高要求”,多CPU、对应用响应时间无要求的中、大型应用。举例:后台处理、科学计算。

--缺点:垃圾收集过程中应用响应时间可能加长

最大垃圾回收暂停:指定垃圾回收时的最长暂停时间,通过-XX:MaxGCPauseMillis=<N>指定。<N>为毫秒.如果指定了此值的话,堆大小和垃圾回收相关参数会进行调整以达到指定值。设定此值可能会减少应用的吞吐量。

吞吐量:吞吐量为垃圾回收时间与非垃圾回收时间的比值,通过-XX:GCTimeRatio=<N>来设定,公式为1/(1+N)。例如,-XX:GCTimeRatio=19时,表示5%的时间用于垃圾回收。默认情况为99,即1%的时间用于垃圾回收。

引用一个网友实例:

 猜想:在HeapSpace逼近临界值的时候,分配小块内存(譬如创建一个对象,如果是分配大块内存,实际上JVM直接就报OutOfMemory了),JVM发现内存不足,会尝试去FullGC出空闲内存,每次还真能挤出一点点,但很快又得重新FullGC,我们知道,实际上FullGC是非常消耗CPU的操作。但为啥不报OutOfMemory呢?因为每次总能够释放出一点点内存,因此竟然就这么维持下去了。这里非常郁闷,JVM直接报OutOfMemory还好过一点,至少直接知道原因。
    JVM一般启动参数有一个GCTimeRatio参数,表示目标吞吐量,JVM会自动调整各内存区大小去达到该吞吐量值,如果吞吐量低于某个值,是会自动OutOfMemory,目前该值默认是1,表示GC时间占总时间不超过1%,但目前来看,要通过这种方式去让JVM直接报告OutOfMemory而不是持续维持高CPU看起来是不行的。
    已经可以定位到是内存达到临界值的问题,接下来问题就简单了,dump出HeapSpace空间,使用Eclipse Memory Analyzer分析一下,原因一目了然,有点讶异,竟然是BlackStar的detail工作模式导致的,这里是因为使用的时候策略没有调整好,调整detail策略,重新启动JVM,问题解决,当然这里BlackStar的detail工作模式的自我保护方式也不好,实际上当发现使用内存过多的时候,应该调整自动放弃。

----------------------------------------------------------------

JStat用于GC分析的参数有:-gc、-gccapacity、-gccause、-gcnew、-gcnewcapacity、-gcold、-gcoldcapacity、-gcpermcapacity、-gcutil。常用的为-gcutil。通过-gcutil可按一定频率查看jvm中各代的空间的占用情况、minor GC的次数、消耗的时间、full GC的次数及消耗的时间的统计,执行jstat -gcutil [pid] [interval],另外可以指定更新频率,如-h5 1s:每一秒更新一次,并每隔5条加上header显示,比如jstat -gcutil  -h5  28525 1s,表示每隔一秒更新一次,并每隔5条加上header显示

可看到类似如下的输出信息:

S0     S1       E      O       P    YGC   YGCT     FGC    FGCT     GCT  

0.00   74.24  96.73  73.43  46.05   17808 382.335  208    315.197  697.533  

45.37   0.00   28.12  74.97  46.05  17809 382.370   208  315.197  697.568

其中S0、S1就是Survivor空间的使用率,E表示Eden空间的使用率,O表示旧生代空间的使用率,P表示持久代的使用率,YGC表示minor GC的执行次数,YGCT表示minor GC执行消耗的时间,FGC表示Full GC的执行次数,FGCT表示Full GC执行消耗的时间,GCT表示Minor GC+Full GC执行消耗的时间。

观察了一下外网数据,每隔两分钟会执行一次minor GC,也就是说Eden空间每隔两分钟就会被充满,然后会填充S0或者S1,填充次序为轮换执行,也就是这次为S0,下次必为S1,

FGC的平均时间为1S左右,minor GC的平均时间为16ms,也就是一个晶振时间,平均一天一次FGC,710次minor GC

对TJ06-盛大3区 gameserver采样

S0:Heap上的 Survivor space 0 段已使用空间的百分比

S1:Heap上的 Survivor space 1 段已使用空间的百分比

E: Heap上的 Eden space 段已使用空间的百分比

O: Heap上的 Old space 段已使用空间的百分比

P: Perm space 已使用空间的百分比

YGC:从程序启动到采样时发生Young GC的次数

YGCT:Young GC所用的时间(单位秒)

FGC:从程序启动到采样时发生Full GC的次数

FGCT:Full GC所用的时间(单位秒)

GCT:用于垃圾回收的总时间(单位秒)

jstat -gccapacity  <jpid>:JVM各区的剩余状态

------------------------------------------------------

jps 目前正在运行中的java进程

-----------------------------------------------------

jstack

jstack -l <jpid>:显示线程阻塞/死锁情况

了解 Java 进程及其对应的执行线程内部发生的情况是一种常见的诊断挑战。例如,当一个应用程序突然停止进程时,很明显出现了资源耗尽,但是仅通过查看代码无法明确知道何处出现资源耗尽,且为什么会发生。

jstack 是一个可以返回在应用程序上运行的各种各样线程的一个完整转储的实用程序,您可以使用它查明问题。

采用期望进程的 VMID 运行 jstack 会产生一个堆转储。就这一点而言,jstack 与在控制台窗口内按 Ctrl-Break 键起同样的作用,在控制台窗口中,Java 进程正在运行或调用 VM 内每个 Thread 对象上的 Thread.getAllStackTraces() 或 Thread.dumpStack()。jstack 调用也转储关于在 VM 内运行的非 Java 线程的信息,这些线程作为 Thread 对象并不总是可用的。

jstack 的 -l 参数提供了一个较长的转储,包括关于每个 Java 线程持有锁的更多详细信息,因此发现(和 squash)死锁或可伸缩性 bug 是极其重要的。

jstack 28065 > /tmp/gg.txt

grep catalina-exec /tmp/ff.txt|wc -l 这个命令是用于查看tomcat的线程池中开启了多少个线程。

----------------------------------------------------

JVM内存状况查看方法和分析工具

Eclipse Memory Analyzer

Eclipse Memory Analyzer是Eclipse提供的一个用于分析jvm堆dump文件的插件,借助这个插件可查看对象的内存占用状况、引用关系、分析内存泄露等。

Eclipse Memory Analyzer(MAT)的网站为:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation,在eclipse中可以直接远程安装此插件。不过由于此插件在分析堆dump文件时比较耗内存,因此在分析前最好先将eclipse的jvm的内存设置大一点,MAT分析dump文件后的对象占用内存及引用关系如图3.23所示。

相对而言MAT功能比jhat强大很多,分析的速度也快一些,因此,如果要分析jvm堆dumap文件,首选推荐的是MAT。

在进行JVM内存状况分析时,通常要关注的主要有GC的趋势、内存的具体消耗状况。

GC趋势对于可图形界面连到需查看GC状况的机器的情况而言,VisualVM是常用的选择;对于不能采用图形界面方式的,输出GC日志 及采用jstat命令直接分析是常用的选择。

在查找内存是程序中的什么对象占用时,需要分析内存的具体消耗状况,对于有图形界面可用的情况,VisualVM是常用的选择;对于不能采用图形界面方式的,可通过jmap dump生成文件后,再通过MAT进行分析是常用的选择。

参考文献:

CMS gc实践总结(纠正并发线程数)

记一次Java GC调整经历

JVM调优牛人博客

最后附上JVM参数调优的案例,其中批注一下-server的参数使用

.-server

 -client

虚拟机服务器模式/客户机模式,使用server模式可以提高性能,启动比client模式慢,长期运行则比client模式快。当该参数不指定时,虚拟机启动检测主机是否为服务器,如果是则以server模式启动,否则以client模式启动,J2SE5.0检测的根据是至少2个CPU和最低2GB内存


jvm.rar


jstat pid not found

今天在用jstat命令的时候,遇到pid not found的问题,然,自己确定pid输入是正确存在的,但为什么呢?

原来运维那边每隔一个月,一般在月底都会去清空一下tmp目录下的文件,导致/tmp/hsperfdata_${user}/${PID}文件没了,

user 例如 是admin  root等等

pid就是 你当前运行的java的pid了。

顺便说下 如果jstat出现 pid not  found ,那用jps也看不到这个进程了。

我这边因为是 这个pid文件被删除了,所以不能看了。

解决方法是重启服务就ok了

----------------------------

JVM 参数优化

-server -Xms2g -Xmx2g -XX:PermSize=96m -XX:MaxPermSize=256m -Xmn1024m -verbose:gc

-Xloggc:/home/yahoo/output/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps

-XX:+UseConcMarkSweepGC

-XX:+DisableExplicitGC

参数

说明

-server

服务机模式,不配置默认的是-client,一定要作为第一个参数,在多个CPU时性能佳

-Xms2g -Xmx2g

堆大小,线上的堆的最大值与最小值必须一致,省得jvm调整堆大小浪费性能。

-Xmn1024m

堆中新生代大小,一般为堆的一半多些

-XX:PermSize=96m -XX:MaxPermSize=256m

jvm方法区空间大小

-Xloggc:/home/yahoo/output/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps

打GC日志,这不会给系统带来啥负担,建议线上机器都加上,方便调优和OutOfMemory后查错。

-verbose:gc

将虚拟机的垃圾回收事件信息打印

-XX:+UseConcMarkSweepGC

新生代采用ParNew GC方式,旧生代采用并发GC方式,以减少系统停顿时间为优先,缩短major收集的时间,此选项在Heap Size 比较大而且Major收集时间较长的情况下使用更合适。

-XX:+DisableExplicitGC

禁止程序触发GC,System.gc()

-Xloggc:gc.log 指定垃圾收集日志文件

-XX:+UseParNewGC :缩短minor收集的时间

 

HeapDumpOnOutOfMemoryError

在jvm的 启动参数中追加 下列信息,可以在发生 OutOfMemoryError的时候生成 oom.hprof文件

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:/temp/oom.hprof

直接内存被占满的话,也会导致FULLGC

目录
相关文章
|
6月前
|
存储 监控 算法
jvm-性能调优(二)
jvm-性能调优(二)
|
8月前
|
Arthas 监控 Java
(十一)JVM成神路之性能调优篇:GC调优、Arthas工具详解及各场景下线上最佳配置推荐
“在当前的互联网开发模式下,系统访问量日涨、并发暴增、线上瓶颈等各种性能问题纷涌而至,性能优化成为了现时代开发过程中炙手可热的名词,无论是在开发、面试过程中,性能优化都是一个常谈常新的话题”。
670 3
|
3月前
|
监控 架构师 Java
Java虚拟机调优的艺术:从入门到精通####
本文作为一篇深入浅出的技术指南,旨在为Java开发者揭示JVM调优的神秘面纱,通过剖析其背后的原理、分享实战经验与最佳实践,引领读者踏上从调优新手到高手的进阶之路。不同于传统的摘要概述,本文将以一场虚拟的对话形式,模拟一位经验丰富的架构师向初学者传授JVM调优的心法,激发学习兴趣,同时概括性地介绍文章将探讨的核心议题——性能监控、垃圾回收优化、内存管理及常见问题解决策略。 ####
|
4月前
|
监控 Java 编译器
Java虚拟机调优指南####
本文深入探讨了Java虚拟机(JVM)调优的精髓,从内存管理、垃圾回收到性能监控等多个维度出发,为开发者提供了一系列实用的调优策略。通过优化配置与参数调整,旨在帮助读者提升Java应用的运行效率和稳定性,确保其在高并发、大数据量场景下依然能够保持高效运作。 ####
64 1
|
4月前
|
存储 算法 Java
JVM进阶调优系列(10)敢向stop the world喊卡的G1垃圾回收器 | 有必要讲透
本文详细介绍了G1垃圾回收器的背景、核心原理及其回收过程。G1,即Garbage First,旨在通过将堆内存划分为多个Region来实现低延时的垃圾回收,每个Region可以根据其垃圾回收的价值被优先回收。文章还探讨了G1的Young GC、Mixed GC以及Full GC的具体流程,并列出了G1回收器的核心参数配置,帮助读者更好地理解和优化G1的使用。
|
4月前
|
监控 Java 测试技术
Elasticsearch集群JVM调优垃圾回收器的选择
Elasticsearch集群JVM调优垃圾回收器的选择
121 1
|
4月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
4月前
|
监控 Java 编译器
Java虚拟机调优实战指南####
本文深入探讨了Java虚拟机(JVM)的调优策略,旨在帮助开发者和系统管理员通过具体、实用的技巧提升Java应用的性能与稳定性。不同于传统摘要的概括性描述,本文摘要将直接列出五大核心调优要点,为读者提供快速预览: 1. **初始堆内存设置**:合理配置-Xms和-Xmx参数,避免频繁的内存分配与回收。 2. **垃圾收集器选择**:根据应用特性选择合适的GC策略,如G1 GC、ZGC等。 3. **线程优化**:调整线程栈大小及并发线程数,平衡资源利用率与响应速度。 4. **JIT编译器优化**:利用-XX:CompileThreshold等参数优化即时编译性能。 5. **监控与诊断工
|
4月前
|
存储 监控 Java
JVM进阶调优系列(8)如何手把手,逐行教她看懂GC日志?| IT男的专属浪漫
本文介绍了如何通过JVM参数打印GC日志,并通过示例代码展示了频繁YGC和FGC的场景。文章首先讲解了常见的GC日志参数,如`-XX:+PrintGCDetails`、`-XX:+PrintGCDateStamps`等,然后通过具体的JVM参数和代码示例,模拟了不同内存分配情况下的GC行为。最后,详细解析了GC日志的内容,帮助读者理解GC的执行过程和GC处理机制。
|
5月前
|
Arthas 监控 数据可视化
JVM进阶调优系列(7)JVM调优监控必备命令、工具集合|实用干货
本文介绍了JVM调优监控命令及其应用,包括JDK自带工具如jps、jinfo、jstat、jstack、jmap、jhat等,以及第三方工具如Arthas、GCeasy、MAT、GCViewer等。通过这些工具,可以有效监控和优化JVM性能,解决内存泄漏、线程死锁等问题,提高系统稳定性。文章还提供了详细的命令示例和应用场景,帮助读者更好地理解和使用这些工具。