首先我们要知道jvm的调优,主要是对那些部分的优化。通过jvm内存模型我们可以,首先是分析遇到的问题,然后通过一些工具或者手段找到问题所在,然后通过一定的措施解决问题,下面我们也将按着这个思路来给出具体的操作。

问题分析

  这个主要是根据我们在运行程序时出现的问题:内存溢出,栈溢出,或者请求停顿。

解决方案

  堆内存溢出的话我们首先看jvm的配置参数:

  • java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0

    -Xmx3550m:设置JVM最大可用内存为3550M。

-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。

-Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5。但是如果设置了年轻代的大小和最大最小对内存,这个值就没有必要设置了。

-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6.一般默认比值为2/8

-XX:MaxPermSize=64m:设置永久代大小为64m。一般设置为物理内存的1/64。(这个可以看着做事方法区的大小,在HotSpot虚拟机中方法去和永久带是一个概念)

-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

jvm的参数详解

栈溢出

  主要有栈溢出两种情景:

  • 线程请求的栈的深度大于虚拟机所允许的最大深度,将抛出StackOverflowError

    栈的深度和设置的-xss的大小以及和局部变量的数量以及大小有关,-xss越小,局部变量个数越多长度越长,深度就越小。栈帧存放着局部变量,方法返回值,这些值越多,或者值越大,那么战阵就越大,占用的内存就越大,栈的深度就越小。

  • 虚拟机在扩展栈时无法申请到足够的空间,将抛出OutOfMemoryError

  栈的大小(虚拟机栈和本地方法栈瓜分的大小)=系统限制的内存的大小-最大堆内存的大小(Xmx)-最大方法区内存(MaxPermSize)-程序计数器(很小)-虚拟机本身耗费的内存(很小)

方法区溢出

  常量池内存溢出:运行时常量池也属于方法区

  其他方法区内存溢出:主要是存放class相关信息的地方。主要是大量使用cglib技术,增强类越多,就需要越大的方法区内存。

使用到的工具

  • jstack:java堆栈跟踪工具

  此工具是查看某个进程下的当前时刻线程的状态信息的,生成虚拟机当前时刻的线程快照,线程快照就是当前虚拟机中每一条线程正在执行的方法堆栈的集合,主要目的是定位线程长时间停顿的原因。

命令格式:

  jstack [ option ] pid

基本参数:

  -F 当'jstack [-l] pid'没有相应的时候强制打印栈信息

  -l 长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.

  -m 打印java和native c/c++框架的所有栈信息. -h | -help打印帮助信息

  pid 需要被打印配置信息的java进程id,可以用jps工具查询

重点关注的线程状态:   

  死锁, Deadlock(重点关注)
  执行中,Runnable
  等待资源, Waiting on condition(重点关注)
  等待获取监视器, Waiting on monitor entry(重点关注)
  暂停,Suspended
  对象等待中,Object.wait() 或 TIMED_WAITING
  阻塞, Blocked(重点关注)
停止,Parked

线程状态解析 

  Deadlock:死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。
  Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换。
  Waiting on condition
    该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写,
  比如当网络数据没有准备好读时,线程处于这种等待状态,而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。在 Java引入 NewIO之前,对于每个网络连接,
  都有一个对应的线程来处理网络的读写操作,即使没有可读写的数据,线程仍然阻塞在读写操作上,这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力。
  在 NewIO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高。
  如果发现有大量的线程都在处在 Wait on condition,从线程 stack看, 正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。
  一种情况是网络非常忙,几 乎消耗了所有的带宽,仍然有大量数据等待网络读 写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。
  所以要结合系统的一些性能观察工具来综合分析,比如 netstat统计单位时间的发送包的数目,如果很明显超过了所在网络带宽的限制 ; 观察 cpu的利用率,如果系统态的 CPU时间,
  相对于用户态的 CPU时间比例较高;如果程序运行在 Solaris 10平台上,可以用 dtrace工具看系统调用的情况,如果观察到 read/write的系统调用的次数或者运行时间遥遥领先;
  这些都指向由于网络带宽所限导致的网络瓶颈。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
  blocked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。
  Waiting for monitor entry 和 in Object.wait():Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。

jstack报告分析

   

     

  可以看到thread1在进行等待获取到锁,此时进入waiting for monitor entry,并是阻塞状态。而main线程提前获取到锁,当由于调用了sleep此时进入到Timed_waiting状态,此时man线程锁住的对象地址是7f3167cf0,而thread1正在等待获取这个锁对象。
prio:线程的优先级
tid:线程id
nid:操作系统映射的线程id, 非常关键,后面再使用jstack时补充;
1103e9000
106692000 :表示线程栈的起始地址。
run():这个方法里面包含的出现问的对象以及代码行号
  从jstack日志中,可以看到:主线程获取到thread2对象上的锁,因此正在执行sleep操作,状态为TIMED_WAINTING, 而thread2由于未获取到thread2对象上的锁,因此处于BLOCKED状态。再细看,thread2 正在"waiting to lock <7f3167cf0>",即试图在地址为7f3167cf0所在的对象获取锁,而该锁却被main线程占有(locked <7f3167cf0>)。main线程正在"waiting on condition",说明正在等待某个条件触发,由jstacktrace来看,此线程正在sleep。
经验:如果在jstack日志发现大量的线程在waiting to lock 某个地址,只要能查到哪个线程获取到锁就可以方便定位问题了
  • jstat:虚拟机统计信息监视工具

    主要显示虚拟机进程中的类装载,内存,垃圾收集,jit编译等运行时的数据,是定位云定期虚拟机问题的首选工具

命令格式:

  jstat -<option> [-t] [-h<lines>] <vmid> [<interva[s|ms]> [<count>]]

参数解释:

  Options — 选项,我们一般使用 -gcutil 查看gc情况

  vmid      — VM的进程号,即当前运行的java进程号

  interval[s|ms]  ——  间隔时间,单位为秒或者毫秒,默认为ms。必须是正整型。

  count     — 打印次数,如果缺省则打印无数次

  选项参数

    jstat工具特别强大,有众多的可选项,详细查看堆内各个部分的使用量,以及加载类的数量。使用时,需加上查看进程的进程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 -gcutil pid:统计gc信息统计。 
      jstat -printcompilation pid:当前VM执行的信息。

使用详情分析

  • jmap:java内存映像工具

  主要是用于生成堆转存快照。

命令行格式:

  jmap [option] LVMID(LVMID指的是进程ID)

option参数:

  • dump : 生成堆转储快照,可以再windows下使用
  • finalizerinfo : 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象,不可以再windows下使用
  • heap : 显示Java堆详细信息,不可以再windows下使用
  • histo : 显示堆中对象的统计信息,包括类,实例数量,合计荣力量。可以再windows下使用
  • permstat : to print permanent generation statistics,不可以再windows下使用
  • F : 当-dump没有响应时,强制生成dump快照,不可以再windows下使用

  

  • jinfo
  • jps
  • jhat

jvm调优工具大全

可视化工具

  • jconsole

  jconsole图形界面分析

  • visualVM

jvm的调优的更多相关文章

  1. JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解

    摘要: JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps.jstack.jmap.jhat.jstat.hprof等小巧的工具,本博客希望 ...

  2. JVM性能调优监控工具jps、jstack、jmap、jhat、jstat使用详解(转VIII)

    JVM本身就是一个java进程,一个java程序运行在一个jvm进程中.多个java程序同时运行就会有多个jvm进程.一个jvm进程有多个线程至少有一个gc线程和一个用户线程. JDK本身提供了很多方 ...

  3. JVM参数调优

    JVM参数调优 JVM参数调优是一个很头痛的问题,可能和应用有关系,下面是本人一些调优的实践经验,希望对读者能有帮助,环境LinuxAS4,resin2.1.17,JDK6.0,2CPU,4G内存,d ...

  4. Java性能优化权威指南-读书笔记(二)-JVM性能调优-概述

    概述:JVM性能调优没有一个非常固定的设置,比如堆大小设置多少,老年代设置多少.而是要根据实际的应用程序的系统需求,实际的活跃内存等确定.正文: JVM调优工作流程 整个调优过程是不断重复的一个迭代, ...

  5. JVM性能调优

    摘自:http://uule.iteye.com/blog/2114697 JVM垃圾回收与性能调优总结 JVM调优的几种策略 一.JVM内存模型及垃圾收集算法  1.根据Java虚拟机规范,JVM将 ...

  6. JVM 性能调优实战之:一次系统性能瓶颈的寻找过程

    玩过性能优化的朋友都清楚,性能优化的关键并不在于怎么进行优化,而在于怎么找到当前系统的性能瓶颈.性能优化分为好几个层次,比如系统层次.算法层次.代码层次…JVM 的性能优化被认为是底层优化,门槛较高, ...

  7. JVM 性能调优实战之:使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码

    本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 提升到 20 (提升了 7 倍) ...

  8. (转)JVM参数调优八大技巧

    这里和大家分享一下JVM参数调优的八条经验,JVM参数调优,这是很头痛的问题,设置的不好,JVM不断执行FullGC,导致整个系统变得很慢,网站停滞时间能达10秒以上,相信通过本文的学习你对JVM参数 ...

  9. JVM的GC机制及JVM的调优方法

    内存管理和垃圾回收是JVM非常关键的点,对Java性能的剖析而言,了解内存管理和垃圾回收的基本策略非常重要. 1.在程序运行过程当中,会创建大量的对象,这些对象,大部分是短周期的对象,小部分是长周期的 ...

  10. jvm 性能调优

    [转载]:http://blog.csdn.net/chen77716/article/details/5695893 最近因项目存在内存泄漏,故进行大规模的JVM性能调优 , 现把经验做一记录. 一 ...

随机推荐

  1. MySQL的binlog日志<转>

    binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二进制日 ...

  2. github新建repositories后import已有code 随后同步更新

    github上,可以forks别人已有的项目,而且同步更新合并也很方便,但如果是自己新建的项目,而导入的是别人的代码修改后,别人的又更新了,自己想获取他的更新,怎么办呢?其实很简单. # git cl ...

  3. 蓝牙mesh介绍

    了解一下关于蓝牙Mesh的知识. 蓝牙mesh网络使用,并且依赖于低功耗蓝牙(BLE).低功耗蓝牙技术是蓝牙mesh使用的无线通信协议栈. 蓝牙BR / EDR能够实现一台设备到另一台设备的连接和通信 ...

  4. 让ubuntu下的eclipse支持GBK编码

    把Windows下工程导入Linux下Eclipse中,由于以前的工程代码,都是GBK编码,而Ubuntu默认不支持GBK编码,所以,我们要让Ubuntu支持GBK,方法如下: 1.修改/var/li ...

  5. Eclipse使用心得与技巧

    一. 常用快捷键(熟练使用快捷键可以充分提高编程效率,吐血整理...) 1,Alt + ↑上方向键:向上移动选中的代码,你可以把一行或者一段代码直接上移几行 2,Alt + ↓下方向键:向下移动选中的 ...

  6. tmux常用配置

    首先创建配置文件 $ touch ~/.tmux.conf 一,鼠标支持 对于version 2.1 (18 October 2015)之后的版本,编辑配置文件.tmux.conf, 保存即可. se ...

  7. Ubuntu下安装hbase

    1.在清华镜像站点下载hbase的安装文件,选择的是stable的版本,版本号是hbase-1.2.5/ 2.解压放在/usr/local的目录下 3.修改权限 sudo chown -R hduse ...

  8. Git使用基础篇

    Git使用基础篇 前言 Git是一个分布式的版本控制工具,本篇文章从介绍Git开始,重点在于介绍Git的基本命令和使用技巧,让你尝试使用Git的同时,体验到原来一个版 本控制工具可以对开发产生如此之多 ...

  9. Qt编写调试日志输出类带网络转发(开源)

    用qt开发商业程序已经九年了,陆陆续续开发过至少几十个程序,除了一些算不算项目的小工具外,大部分的程序都需要有个日志的输出功能,希望可以将程序的运行状态存储到文本文件或者数据库或者做其他处理等,qt对 ...

  10. Android性能测试--内存

    前言: 近阶段都在探索android性能测试方面的东西,其中一个很重要的指标就是内存.对于内存,主要是一些gc是不是及时,或者说一些引用有没有及时释放,有没有导致oom或者内存持续增加导致卡顿,有没有 ...