`

探究JVM内存泄露 性能调优的基本知识和JDK调优

    博客分类:
  • java
 
阅读更多

 基本知识

1.1 性能是什么

在性能调优之前,我们首先来了解一下性能是什么?关于性能,我想每个学习过 Java 的人都能列出几点,甚至可以夸夸其谈。在《 Java TM Platform Performance 》一书中,定义了如下五个方面来作为评判性能的标准:

1) 运算的性能——哪一个算法的执行性能最好?

2) 内存的分配——程序运行时需要耗费多少内存?

3) 启动的时间——程序启动需要多长时间?这在 Web 项目中的影响不大,但要注意部分程序需要部署或运行在客户端时的情形(比如 applet 程序)。

4) 程序的可伸缩性——在压力负载的情况下,程序的性能如何?

5) 性能的感知——用户在什么情况下会觉得程序的性能不好?

以上五个方面,在具体的使用场景可以有选择的去评判。至于这五方面的性能调优,在后续的章节中将会陆续的给以相应的性能调优策略。

1.2 调优的规则

我们只需要关心对我们程序有影响,可以察觉到的性能问题,而不是每一个类中的每一个方法我们都需要想方设法的提高性能。如果程序的性能没有达到我们所期望的要求,我们才需要考虑如何优化性能。同样的,晦涩的代码虽然提高了程序的性能,但同时可能带给我们的是维护的噩梦。我们需要折中的考虑以上两种情况,使得程序的代码是优美的,并且运行的足够快,达到客户所期望的性能要求。

优化代码甚至会导致不良的结果, Donald Knuth (一位比较牛比较有影响的人物,具体是谁,我也忘了,谁知道,可以告诉我一下,谢谢!)曾说过,“ Premature optimization is the root of all evil” 。在开始性能调优前,需要先指出不优化代码的一些理由。

1) 如果优化的代码已经正常工作,优化后可能会引入新的 bug 

2) 优化代码趋向于使代码更难理解和维护;

3) 在一个平台上优化的代码,在另一个平台上可能更糟;

4) 花费很多时间在代码的优化上,提高了很少的性能,却导致了晦涩的代码。

确实,在优化前,我们必须认真的考虑是否值得去优化。

1.3 调优的步骤

一般我们提高应用程序的性能划分为以下几个步骤:

1) 明确应用程序的性能指标,怎样才符合期望的性能需求;

2) 在目标平台进行测试;

3) 如果性能已经达到性能指标, Stop 

4) 查找性能瓶颈;

5) 修改性能瓶颈;

6) 返回到第 步。

 JDK 调优

2.1 选择合适的 JDK 版本

不同版本的 JDK ,甚至不同厂家的 JDK 可能都存在着很大的差异,对于性能优化的程度不同。一般来说,尽可能选择最新发布的稳定的 JDK 版本。最新的稳定的 JDK 版本相对以前的 JDK 版本都会做一些 bug 的修改和性能的优化工作。

2.2 垃圾收集 Java 堆的优化

垃圾收集就是自动释放不再被程序所使用的对象的过程。当一个对象不再被程序所引用时,它所引用的堆空间可以被回收,以便被后续的新对象所使用。垃圾收集器必须能够断定哪些对象是不再被引用的,并且能够把它们所占据的堆空间释放出来。如果对象不再被使用,但还有被程序所引用,这时是不能被垃圾收集器所回收的,此时就是所谓的“内存泄漏”。监控应用程序是否发生了内存泄漏,有一个非常优秀的监控工具推荐给大家——Quest 公司的 JProbe 工具,使用它来观察程序运行期的内存变化,并可产生内存快照,从而分析并定位内存泄漏的确切位置,可以精确定位到源码内。这个工具的使用我在后续的章节中还会做具体介绍。

Java 堆是指在程序运行时分配给对象生存的空间。通过 -mx/-Xmx  -ms/-Xms 来设置起始堆的大小和最大堆的大小。根据自己 JDK 的版本和厂家决定使用 -mx  -ms  -Xmx  -Xms  Java 堆大小决定了垃圾回收的频度和速度, Java 堆越大,垃圾回收的频度越低,速度越慢。同理, Java 堆越小,垃圾回收的频度越高,速度越快。要想设置比较理想的参数,还是需要了解一些基础知识的。

Java 堆的最大值不能太大,这样会造成系统内存被频繁的交换和分页。所以最大内存必须低于物理内存减去其他应用程序和进程需要的内存。而且堆设置的太大,造成垃圾回收的时间过长,这样将得不偿失,极大的影响程序的性能。以下是一些经常使用的参数设置:

1) 设置 -Xms 等于 -XmX 的值;

2) 估计内存中存活对象所占的空间的大小,设置 -Xms 等于此值, -Xmx 四倍于此值;

3) 设置 -Xms 等于 -Xmx  1/2 大小;

4) 设置 -Xms 介于 -Xmx  1/10  1/4 之间;

5) 使用默认的设置。

大家需要根据自己的运行程序的具体使用场景,来确定最适合自己的参数设置。

除了 -Xms  -Xmx 两个最重要的参数外,还有很多可能会用到的参数,这些参数通常强烈的依赖于垃圾收集的算法,所以可能因为 JDK 的版本和厂家而有所不同。但这些参数一般在 Web 开发中用的比较少,我就不做详细介绍了。在实际的应用中注意设置 -Xms  -Xmx 使其尽可能的优化应用程序就行了。对于性能要求很高的程序,就需要自己再多研究研究 Java 虚拟机和垃圾收集算法的机制了。可以看看曹晓钢翻译的《深入 Java 虚拟机》一书。

 

 

WEB 服务总是莫名其妙的运行一段时间后 JVM 直接 OutOfMemory 错误,内存泄漏的问题不容易查找,本文就一些查找内存泄露基本知识做个总结,未涉及到具体案例的分析。

1 JVM 内存异常的数据显示
1.1 java.lang.OutOfMemoryError: PermGen space 异常的例子

 

Heap 
PSYoungGen total 44928K, used 916K [0x4e3c0000, 0x50fe0000, 0x51b10000) 
eden space 44736K, 2% used [0x4e3c0000,0x4e4a5318,0x50f70000) 
from space 192K, 0% used [0x50f70000,0x50f70000,0x50fa0000) 
to space 192K, 0% used [0x50fb0000,0x50fb0000,0x50fe0000) 
PSOldGen total 453312K, used 125529K [0x32910000, 0x4e3c0000, 0x4e3c0000)
object space 453312K, 27% used [0x32910000,0x3a3a6498,0x4e3c0000) 
PSPermGen total 65536K, used 65535K [0x2e910000, 0x32910000, 0x32910000) 
object space 65536K, 99% used [0x2e910000,0x3290fff8,0x32910000)

permanent space 持久空间 用于类和方法对象的存储。 spring  AOP 时使用 CBLIB 会动态产生很多类,当类太多,超过 MaxPermSize 的时候,就会抛出此异常。 参数问题 可以设置 jvm 启动参数 : PermSize, MaxPermSize 。程序问题就要进行内存分析了,详见下文。

1.2 java.lang.OutOfMemoryError: Java heap space 异常的例子

 

Heap
PSYoungGen total 88320K, used 67673K [0x44880000, 0x4ba40000, 0x4ba40000)
eden space 61952K, 100% used [0x44880000,0x48500000,0x48500000)
from space 26368K, 21% used [0x48500000,0x48a96490,0x49ec0000)
to space 24512K, 16% used [0x4a250000,0x4a6283e0,0x4ba40000)
PSOldGen total 932096K, used 582090K [0x0ba40000, 0x44880000, 0x44880000)
object space 932096K, 62% used [0x0ba40000,0x2f2b2a78,0x44880000)
PSPermGen total 131072K, used 35124K [0x03a40000, 0x0ba40000, 0x0ba40000)
object space 131072K, 26% used [0x03a40000,0x05c8d330,0x0ba40000)

eden space 使用率 100% ,总是被占满,参数问题 可以设置 jvm 启动参数 : Xms, Xmx 。程序问题就要进行内存分析了,详见下文。

1.3 查看 jvm 内存状态:

jstat -gcutil pid 1000 20

异常情况的例子

jstat -gcutil pid 1000 20

 

S0 S1 E O P YGC YGCT FGC FGCT GCT 
0.00 0.00 99.99 82.51 53.11 2409 1.205 10117 7250.393 7251.598
0.00 0.00 83.42 82.55 53.10 2409 1.205 10118 7252.650 7253.855
0.00 0.00 56.06 82.46 53.10 2410 1.205 10120 7254.467 7255.672
0.00 0.00 32.11 82.55 53.10 2411 1.205 10121 7256.673 7257.877
0.00 0.00 99.99 82.55 53.10 2412 1.205 10123 7257.026 7258.231
0.00 0.00 76.00 82.50 53.10 2412 1.205 10124 7259.241 7260.446

这个数据显示 Full GC 频繁发生。

 

正常情况的例子

 

S0 S1 E O P YGC YGCT FGC FGCT GCT

0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

参数含义: 
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
 :用于垃圾回收的总时间 ( 单位秒 )

2 Dump 出内存
2.1 找出要 dump 的线程 pid

 

 windows 下,使用 tasklist

 Linux 下,使用 ps –aux

2.2 Dump 出内存使用详情

可以通过命令:

 

jmap -dump:file=a.hprof pid

也可以通过 jconsole 的图形界面操作。

 

在命令行键入: jconsole

Jconsole 打开后在造作下选择 dumpHeap, 输入参数 p0,p1;p0 表示 dump 出来的文件路径,后缀为 .hprof p1 设为 true ,表示只分析活着的对象。

jvm调优总结

 

3 使用内存分析工具

目前有很多用来分析 Java 内存对象的工具,如收费的工具有 jprofiler, 而像 Eclipse MAT 则是优秀的内存对象分析开源工具 . 它们对于分析内存溢出问题非常有用。以下是一个安装使用 Eclipse MAT 的简单例子。

3.1 装一个 Eclipse 的内存分析插件 MAT

http://download.eclipse.org/technology/mat/latest/update-site/

 

3.2 切换到 Memory Analysis 模式
jvm调优总结

 

3.3 通过 File > Open Heap Dump.... 查看 dump 出来的文件

 

jvm调优总结

4 JDK 自带的 JVM 查看分析工具 jps  jmap  jstat  jconsole
4.1 jps

Java 进程查看工具,实际上它和 Unix/Linux 上面的 ps 命令的功能差不多

4.2 jmap

jmap 是一个可以输出所有内存中对象的工具 .

* -dump:format=b,file=<filename> 转存堆内存到本地文件。 
* -histo 
打印堆里每个类的情况,包含内存占用大小、对象数量及完整类名。 VM 的内部类以 "*" 开头。

例子:

 

jmap -histo pid>a.log

jmap -dump: file=a.hprof pid

查看 a.log

 

num #instances #bytes class name
--------------------------------------
1: 427398 14458448 [I
2: 178798 6830216 [C
3: 50278 6668512 <constMethodKlass>
4: 179924 4318176 java.lang.String
5: 50278 4026648 <methodKlass>
6: 15244 3894200 [B
7: 47809 1773776 [Ljava.lang.Object;
...
Total 1645187 81806088

说明:

#instance 是对象的实例个数 
#bytes 
是总占用的字节数 
class name 
对应的就是 Class 文件里的 class 的标识 
B 
代表 byte
C
 
代表 
char
D
 
代表 
double
F
 
代表 
float
I
 
代表 
int
J
 
代表 
long
Z
 
代表 
boolean
前边有 [ 代表数组, [I 就相当于 int[]

对象用 [L+ 类名表示

4.3 jstat

jstat  vm 的状态监控工具,监控的内容有类加载、运行时编译及 GC 

使用时,需加上查看进程的进程 id ,和所选参数。以下详细介绍各个参数的意义。 
jstat -class pid:
 显示加载 class 的数量,及所占空间等信息。 
jstat -compiler pid:
 显示 VM 实时编译的数量等信息。 
jstat -gc pid:
 可以显示 gc 的信息,查看 gc 的次数,及时间。其中最后五项,分别是 young gc 的次数,young gc 的时间, full gc 的次数, full gc 的时间, gc 的总时间。 
jstat -gccapacity:
 可以显示, VM 内存中三代( young,old,perm )对象的使用和占用大小,如: PGCMN显示的是最小 perm 的内存使用量, PGCMX 显示的是 perm 的内存最大使用量, PGC 是当前新生成的 perm 内存占用量, PC 是但前 perm 内存占用量。其他的可以根据这个类推, OC  old 内纯的占用量。 
jstat -gcnew pid:new
 对象的信息。 
jstat -gcnewcapacity pid:new
 对象的信息及其占用量。 
jstat -gcold pid:old
 对象的信息。 
jstat -gcoldcapacity pid:old
 对象的信息及其占用量。 
jstat -gcpermcapacity pid: perm
 对象的信息及其占用量。 
jstat -util pid:
 统计 gc 信息统计。 
jstat -printcompilation pid:
 当前 VM 执行的信息。 
除了以上一个参数外,还可以同时加上 两个数字,如: jstat -printcompilation 3024 250 6 是每 250毫秒打印一次,一共打印 6次,还可以加上 -h3 每三行显示一下标题。 
例子:

 

jstat -gcutil pid 1000 20

4.4 jconsole

一个 java GUI 监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器 VM 

分享到:
评论

相关推荐

    JVM系列之性能调优参考手册(实践篇).pdf

    标题《JVM系列之性能调优参考手册(实践篇)》涉及的知识点主要集中在Java虚拟机(JVM)性能调优的实践操作。JVM作为Java程序运行的基础环境,对程序性能有着决定性影响。本手册的目的是指导开发者如何对JVM进行性能...

    推荐一些JVM原理,JVM调优,JVM内存模型,JAVA并发 电子书1

    总的来说,JVM原理、JVM调优、JVM内存模型和JAVA并发是Java程序员和系统管理员需要深入了解的知识点,因为它们直接影响到Java程序的性能和稳定性。了解这些知识点有助于开发者编写性能更优的代码,并在生产环境中对...

    jvm内存监控及调优方法

    jvm内存监控及调优方法,详细讲解jvm的原理以及常用调优手段

    JVM3天性能调优教程

    JVM3天性能调优教程.txt

    JVM内存管理及调优

    毕玄,一位在淘宝有着丰富经验的专家,通过他的演讲PPT,我们能深入理解JVM内存的实现、使用和调优。 ### 一、JVM内存实现 JVM内存主要分为以下几个区域: 1. **程序计数器(Program Counter Register)**:记录...

    java -jvm 内存分配和jvm调优

    总结,Java JVM内存分配和调优是一项复杂的任务,需要结合实际应用的需求和性能指标来调整。通过理解JVM内存模型,选择合适的垃圾收集器和设置合理的内存参数,可以有效提升Java应用的性能和稳定性。在实践中,不断...

    深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理).zip

    《深入理解Java虚拟机》是一本深度探讨Java虚拟机(JVM)的著作,涵盖了JVM性能调优、内存模型以及虚拟机原理等多个关键领域。本文将基于这些主题,详细阐述其中的重要知识点。 首先,我们要了解Java虚拟机(JVM)...

    jvm性能调优+内存模型+虚拟机

    jvm性能调优+内存模型+虚拟机 jvm性能调优+内存模型+虚拟机 jvm性能调优+内存模型+虚拟机

    涨见识!JVM性能监控与调优实战 一线大厂大牛讲师的JVM优化案例与解决方案课程

    课程前端讲解了JVM的性能监控和调优的概述,对调优的的方法和工具进行讲解学习,让同学们掌握方法,理解知识。课程的中间阶段我们进行了优化思想上的灌输,是整体课程衔接非常重要的部分。而后篇则更加的注重实战和...

    JVM内存管理、调优与监控考据

    Java虚拟机(JVM)内存管理、调优与监控是Java开发者关注的重要话题,因为它们直接影响到应用程序的性能和稳定性。本文将从JVM内存结构、调优策略以及监控工具等多个角度进行深入考据。 首先,JVM内存分为几个主要...

    JAVA应用JVM原理及参数调优深入讲解视频.zip

    JAVA应用JVM原理及参数调优深入讲解视频.1 JAVA应用JVM原理及参数调优深入讲解视频.2 JAVA应用JVM原理及参数调优深入讲解视频.3 JAVA应用JVM原理及参数调优深入讲解视频.4 JAVA应用JVM原理及参数调优深入讲解视频.5 ...

    JVM内存设置与调优指南

    总的来说,JVM内存设置与调优是一门深奥的学问,需要根据具体应用进行细致的分析和实验,以达到最佳的性能表现。理解内存结构、选择合适的垃圾收集器、合理设置参数,并结合监控工具进行调优,是优化Java应用性能的...

    JVM的基础和调优【JMM 内存结构 GC OOM 性能调优 ThreadLocal】

    JVM的基础和调优【JMM 内存结构 GC OOM 性能调优 ThreadLocal】 内存泄露:是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄露, 一次的内存泄露似乎不会有大的影响,但是内存泄露堆积的后果就是内存...

    个人总结之—JVM性能调优实战

    本文档总结了作者在实践中不断积累的JVM性能调优经验,涵盖了JVM基础知识、内存调优策略、常见性能问题及解决方案等多个方面。希望通过这份总结能够为广大读者提供有价值的参考和帮助,提升应用性能,优化用户体验。...

    JVM 内存管理及调优.zip_JVM内存_java_memory

    Java虚拟机(JVM)内存管理与调优是Java开发中的关键环节,它涉及到程序的性能、稳定性和资源效率。JVM内存分为多个区域,包括堆内存、方法区、程序计数器、虚拟机栈和本地方法栈。理解这些区域的工作原理以及如何...

    JVM性能调优-JVM内存整理及GC回收.pdf

    在Java编程语言中,方法参数的传递方式是一个重要知识点。Java方法参数的传递分为值传递和引用传递...这些知识点对于准备Java面试的开发者来说,是必须掌握的重要内容,同时也是深入理解JVM内存管理和性能优化的基础。

    JVM入门到JVM 调优实战

    实际调优过程中,需要根据系统负载、应用类型和性能需求进行细致调整。 【垃圾回收算法】 垃圾回收算法有多种,如分代收集、标记-清除、复制、标记-整理、CMS(Concurrent Mark Sweep)、G1(Garbage-First)等。每...

    JVM基础知识及性能调优

    ### JVM基础知识及性能调优 #### 一、JVM架构概览 Java虚拟机(JVM)作为Java程序运行的基础环境,其内部结构复杂且高效。理解JVM的基础知识对于优化Java应用程序至关重要。JVM主要由以下几个关键部分组成: 1. **...

    阿里巴巴Java性能调优实战(2021华山版)

    模块四主要讲解 JVM 性能监测及调优,包括 Java 对象的创建和回收、内存分配等。 模块五:设计模式调优 模块五主要讲解设计模式调优,包括架构设计中使用设计模式来优化架构设计的经验和实践。 模块六:数据库...

    JVM性能调优总结.docx

    JVM性能调优是Java开发中非常重要的一方面,直接影响到系统的性能和稳定性。本文将总结JVM性能调优的经验和技巧,并提供一些实用的配置参数和建议。 一、堆大小设置 堆大小是JVM性能调优中的一个关键参数。堆大小...

Global site tag (gtag.js) - Google Analytics