码迷,mamicode.com
首页 > 其他好文 > 详细

jvm的调优

时间:2018-03-21 17:33:07      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:erro   线程等待   管理器   进入   物理内存   运行时间   jhat   tsp   参数详解   

  首先我们要知道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堆栈跟踪工具

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

  重点关注的线程状态:   

死锁, 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 :表示线程栈的起始地址。
从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
  • jmap
  • jinfo
  • jps
  • jhat

 

可视化工具

  • jconsole
  • visualVM

jvm的调优

标签:erro   线程等待   管理器   进入   物理内存   运行时间   jhat   tsp   参数详解   

原文地址:https://www.cnblogs.com/htyj/p/8618009.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!