前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >虚拟机11.JVM调优_调优方法

虚拟机11.JVM调优_调优方法

作者头像
Java帮帮
发布2018-03-15 17:40:22
9250
发布2018-03-15 17:40:22
举报

虚拟机11.JVM调优_调优方法

ENTER TITLE

JVM调优工具

Jconsole,jProfile,VisualVM

Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪。详细说明参考这里

JProfiler:商业软件,需要付费。功能强大。详细说明参考这里

VisualVM:JDK自带,功能强大,与JProfiler类似。推荐。

如何调优

观察内存释放情况、集合类检查、对象树

上面这些调优工具都提供了强大的功能,但是总的来说一般分为以下几类功能

堆信息查看

可查看堆空间大小分配(年轻代、年老代、持久代分配)

提供即时的垃圾回收功能

垃圾监控(长时间监控回收情况)

查看堆内类、对象信息查看:数量、类型等

对象引用情况查看

有了堆信息查看方面的功能,我们一般可以顺利解决以下问题:

--年老代年轻代大小划分是否合理

--内存泄漏

--垃圾回收算法设置是否合理

线程监控

线程信息监控:系统线程数量。

线程状态监控:各个线程都处在什么样的状态下

Dump线程详细信息:查看线程内部运行情况

死锁检查

热点分析

CPU热点:检查系统哪些方法占用的大量CPU时间

内存热点:检查哪些对象在系统中数量最大(一定时间内存活对象和销毁对象一起统计)

这两个东西对于系统优化很有帮助。我们可以根据找到的热点,有针对性的进行系统的瓶颈查找和进行系统优化,而不是漫无目的的进行所有代码的优化。

快照

快照是系统运行到某一时刻的一个定格。在我们进行调优的时候,不可能用眼睛去跟踪所有系统变化,依赖快照功能,我们就可以进行系统两个不同运行时刻,对象(或类、线程等)的不同,以便快速找到问题

举例说,我要检查系统进行垃圾回收以后,是否还有该收回的对象被遗漏下来的了。那么,我可以在进行垃圾回收前后,分别进行一次堆情况的快照,然后对比两次快照的对象情况。

内存泄漏检查

内存泄漏是比较常见的问题,而且解决方法也比较通用,这里可以重点说一下,而线程、热点方面的问题则是具体问题具体分析了。

内存泄漏一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而导致新的资源分配请求无法完成,引起系统错误。

内存泄漏对系统危害比较大,因为他可以直接导致系统的崩溃。

需要区别一下,内存泄漏和系统超负荷两者是有区别的,虽然可能导致的最终结果是一样的。内存泄漏是用完的资源没有回收引起错误,而系统超负荷则是系统确实没有那么多资源可以分配了(其他的资源都在使用)。

年老代堆空间被占满

异常: java.lang.OutOfMemoryError: Java heap space

说明:

这是最典型的内存泄漏方式,简单说就是所有堆空间都被无法回收的垃圾对象占满,虚拟机无法再在分配新空间。

如上图所示,这是非常典型的内存泄漏的垃圾回收情况图。所有峰值部分都是一次垃圾回收点,所有谷底部分表示是一次垃圾回收后剩余的内存。连接所有谷底的点,可以发现一条由底到高的线,这说明,随时间的推移,系统的堆空间被不断占满,最终会占满整个堆空间。因此可以初步认为系统内部可能有内存泄漏。(上面的图仅供示例,在实际情况下收集数据的时间需要更长,比如几个小时或者几天)

解决:

这种方式解决起来也比较容易,一般就是根据垃圾回收前后情况对比,同时根据对象引用情况(常见的集合对象引用)分析,基本都可以找到泄漏点。

持久代被占满

异常:java.lang.OutOfMemoryError: PermGen space

说明:

Perm空间被占满。无法为新的class分配存储空间而引发的异常。这个异常以前是没有的,但是在Java反射大量使用的今天这个异常比较常见了。主要原因就是大量动态反射生成的类不断被加载,最终导致Perm区被占满。

更可怕的是,不同的classLoader即便使用了相同的类,但是都会对其进行加载,相当于同一个东西,如果有N个classLoader那么他将会被加载N次。因此,某些情况下,这个问题基本视为无解。当然,存在大量classLoader和大量反射类的情况其实也不多。

解决:

1. -XX:MaxPermSize=16m

2. 换用JDK。比如JRocket。

堆栈溢出

异常:java.lang.StackOverflowError

说明:这个就不多说了,一般就是递归没返回,或者循环调用造成

线程堆栈满

异常:Fatal: Stack size too small

说明:java中一个线程的空间大小是有限制的。JDK5.0以后这个值是1M。与这个线程相关的数据将会保存在其中。但是当线程空间满了以后,将会出现上面异常。

解决:增加线程栈大小。-Xss2m。但这个配置无法解决根本问题,还要看代码部分是否有造成泄漏的部分。

系统内存被占满

异常:java.lang.OutOfMemoryError: unable to create new native thread

说明

这个异常是由于操作系统没有足够的资源来产生这个线程造成的。系统创建线程时,除了要在Java堆中分配内存外,操作系统本身也需要分配资源来创建线程。因此,当线程数量大到一定程度以后,堆中或许还有空间,但是操作系统分配不出资源来了,就出现这个异常了。

分配给Java虚拟机的内存愈多,系统剩余的资源就越少,因此,当系统内存固定时,分配给Java虚拟机的内存越多,那么,系统总共能够产生的线程也就越少,两者成反比的关系。同时,可以通过修改-Xss来减少分配给单个线程的空间,也可以增加系统总共内生产的线程数。

解决:

1. 重新设计系统减少线程数量。

2. 线程数量不能减少的情况下,通过-Xss减小单个线程大小。以便能生产更多的线程。

JVM 几个重要的参数

<本文提供的设置仅仅是在高压力,多CPU,高内存环境下设置>

最近对JVM的参数重新看了下,把应用的JVM参数调整了下。 几个重要的参数 -server -Xmx3g -Xms3g -XX:MaxPermSize=128m -XX:NewRatio=1 eden/old 的比例 -XX:SurvivorRatio=8 s/e的比例 -XX:+UseParallelGC -XX:ParallelGCThreads=8 -XX:+UseParallelOldGC 这个是JAVA 6出现的参数选项 -XX:LargePageSizeInBytes=128m 内存页的大小,不可设置过大,会影响Perm的大小。 -XX:+UseFastAccessorMethods 原始类型的快速优化 -XX:+DisableExplicitGC 关闭System.gc() 另外 -Xss 是线程栈的大小,这个参数需要严格的测试,一般小的应用,如果栈不是很深,应该是128k够用的,不过,我们的应用调用深度比较大,还需要做详细的测试。这个选项对性能的影响比较大。建议使用256K的大小.

例子:

-server -Xmx3g -Xms3g -Xmn=1g -XX:MaxPermSize=128m -Xss256k -XX:MaxTenuringThreshold=10 -XX:+DisableExplicitGC -XX:+UseParallelGC -XX:+UseParallelOld GC -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+AggressiveOpts -XX:+UseBiasedLocking

-XX:+PrintGCApplicationStoppedTime -XX:+PrintGCTimeStamps -XX:+PrintGCDetails 打印参数

=================================================================

另外对于大内存设置的要求:

Linux : Large page support is included in 2.6 kernel. Some vendors have backported the code to their 2.4 based releases. To check if your system can support large page memory, try the following: # cat /proc/meminfo | grep Huge HugePages_Total: 0 HugePages_Free: 0 Hugepagesize: 2048 kB #

If the output shows the three "Huge" variables then your system can support large page memory, but it needs to be configured. If the command doesn't print out anything, then large page support is not available. To configure the system to use large page memory, one must log in as root, then:

1. Increase SHMMAX value. It must be larger than the Java heap size. On a system with 4 GB of physical RAM (or less) the following will make all the memory sharable: # echo 4294967295 > /proc/sys/kernel/shmmax

2. Specify the number of large pages. In the following example 3 GB of a 4 GB system are reserved for large pages (assuming a large page size of 2048k, then 3g = 3 x 1024m = 3072m = 3072 * 1024k = 3145728k, and 3145728k / 2048k = 1536): # echo 1536 > /proc/sys/vm/nr_hugepages

Note the /proc values will reset after reboot so you may want to set them in an init script (e.g. rc.local or sysctl.conf).

============================================= 这个设置,目前观察下来的结果是EDEN区域收集明显速度比较快,最多几个ms, 但是,对于FGC,大约需要0。9,但是发生时间非常的长,应该是影响不大。但是对于非web应用的中间件服务, 这个设置很要不得, 可能导致很严重延迟效果. 因此, CMS必然需要被使用, 下面是CMS的重要参数介绍 关于CMS的设置:

使用CMS的前提条件是你有比较的长生命对象,比如有200M以上的OLD堆占用。那么这个威力非常猛,可以极大的提高的FGC的收集能力。如果你的OLD占用非常的少,别用了,绝对降低你性能,因为CMS收集有2个STOP WORLD的行为。 OLD少的清情况,根据我的测试,使用并行收集参数会比较好。

-XX:+UseConcMarkSweepGC 使用CMS内存收集 -XX:+AggressiveHeap 特别说明下:(我感觉对于做java cache应用有帮助)

· 试图是使用大量的物理内存

· 长时间大内存使用的优化,能检查计算资源(内存,处理器数量)

· 至少需要256MB内存

· 大量的CPU/内存,(在1.4.1在4CPU的机器上已经显示有提升)

-XX:+UseParNewGC 允许多线程收集新生代 -XX:+CMSParallelRemarkEnabled 降低标记停顿

-XX+UseCMSCompactAtFullCollection 在FULL GC的时候,压缩内存, CMS是不会移动内存的,因此,这个非常容易产生碎片,导致内存不够用,因此,内存的压缩这个时候就会被启用。增加这个参数是个好习惯。

压力测试下合适结果:

-server -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:MaxTenuringThreshold=31 -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods

由于Jdk1.5.09及之前的bug, 因此, CMS下的GC,在这些版本的表现是十分糟糕的。 需要另外2个参数来控制cms的启动时间:

-XX:+UseCMSInitiatingOccupancyOnly 仅仅使用手动定义初始化定义开始CMS收集

-XX:CMSInitiatingOccupancyFraction=70 CMS堆上,使用70%后开始CMS收集。

使用CMS的好处是用尽量少的新生代、,我的经验值是128M-256M,然后老生代利用CMS并行收集,这样能保证系统低延迟的吞吐效率。实际上cms的收集停顿时间非常的短,2G的内存,大约20-80ms的应用程序停顿时间。

=========系统情况介绍========================

这个例子是测试系统12小时运行后的情况:

$uname -a

2.4.21-51.EL3.customsmp #1 SMP Fri Jun 27 10:44:12 CST 2008 i686 i686 i386 GNU/Linux

$ free -m total used free shared buffers cached Mem: 3995 3910 85 0 162 1267 -/+ buffers/cache: 2479 1515 Swap: 2047 0 2047

$ jstat -gcutil 23959 1000

S0 S1 E O P YGC YGCT FGC FGCT GCT 59.06 0.00 45.77 44.45 56.88 15204 324.023 66 1.668 325.691 0.00 39.66 27.53 44.73 56.88 15205 324.046 66 1.668 325.715 53.42 0.00 22.80 44.73 56.88 15206 324.073 66 1.668 325.741 0.00 44.90 13.73 44.76 56.88 15207 324.094 66 1.668 325.762 51.70 0.00 19.03 44.76 56.88 15208 324.118 66 1.668 325.786 0.00 61.62 19.44 44.98 56.88 15209 324.148 66 1.668 325.816 53.03 0.00 14.00 45.09 56.88 15210 324.172 66 1.668 325.840 53.03 0.00 87.87 45.09 56.88 15210 324.172 66 1.668 325.840 0.00 50.49 72.00 45.22 56.88 15211 324.198 66 1.668 325.866

GC参数配置:

JAVA_OPTS=" -server -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:MaxTenuringThreshold=31 -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "

实际上我们可以看到并行young gc执行时间是: 324.198s/15211=20ms, cms的执行时间是 1.668/66=25ms. 当然严格来说,这么算是不对的,世界停顿的时间要比这是数据稍微大5-10ms. 对我们来说如果不输出日志,对我们是有参考意义的。

32位系统下,设置成2G,非常危险,除非你确定你的应用占用的native内存很少,不然可能导致jvm直接crash。

-XX:+AggressiveOpts 加快编译

-XX:+UseBiasedLocking 锁机制的性能改善。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-11-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java帮帮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JVM调优工具
  • 如何调优
  • 线程监控
  • 内存泄漏检查
  • JVM 几个重要的参数
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档