【深入浅出-VisualVM】(4): 分析CPU

栏目: Java · 发布时间: 4年前

内容简介:有时候好好的程序放到生产服务器上一段时间后,就会发现服务器响应缓慢,进而进一步发现是cpu过高,于是就慌了,造成cpu过高的原因很多,不过大多是由于资源吃紧造成,例如:sql执行过慢,程序里存在死循环,数据库连接未释放,网络阻塞导致的第三方框架代码出现死循环,大量的操作导致死锁等,遇到此类问题不必紧张,coder君手把手教你克服心理障碍。VisualVm只能定位JVM的cpu情况,但是生产主机上不光是Java程序,这时我们要采取另外的方案。

有时候好好的程序放到生产服务器上一段时间后,就会发现服务器响应缓慢,进而进一步发现是cpu过高,于是就慌了,造成cpu过高的原因很多,不过大多是由于资源吃紧造成,例如:sql执行过慢,程序里存在死循环,数据库连接未释放,网络阻塞导致的第三方框架代码出现死循环,大量的操作导致死锁等,遇到此类问题不必紧张,coder君手把手教你克服心理障碍。

案例:死循环造成CPU过高

public class CpuTest {
 
    public static void main(String[] args) throws InterruptedException {
        loop();
        endlessLoop();
    }
 
 
    public static void endlessLoop() throws InterruptedException {
 
        while (true) {
            System.out.println("hello world! loop!");
        }
    }
 
    public static void loop(){
        for (int i = 0; i < 10000; i++) {
            System.out.println("hello world! endless loop!");
        }
    }
}

分析点击抽样器->CPU->查看CPU样例,发现endlessLoop()方法最耗CPU(这里有2个方法 loop和endlessLoop)

【深入浅出-VisualVM】(4): 分析CPU

查看线程cpu耗时,发现main线程最耗时,点击增量,可以从此刻观察,cpu耗时的增长速率

【深入浅出-VisualVM】(4): 分析CPU

查看线程dump,主要观察main线程,发现main线程当前状态下一直在执行 CpuTest.endlessLoop(CpuTest.java:14) ,这里可以定位问题位置,同时细心的童鞋可以观察看后面执行System.out.println(“”);方法是要先加锁的。

【深入浅出-VisualVM】(4): 分析CPU

截图一段,我生产服务器(tomcat+springmvc)main线程的情况,其实只想说明web项目启动的main方法在中间件里。

【深入浅出-VisualVM】(4): 分析CPU

【深入浅出-VisualVM】(4): 分析CPU

补充

VisualVm只能定位JVM的cpu情况,但是生产主机上不光是 Java 程序,这时我们要采取另外的方案。

1.看监控数据是否正常,cpu,mem。

【深入浅出-VisualVM】(4): 分析CPU

【深入浅出-VisualVM】(4): 分析CPU

CPU占用1.5左右(100-98.0id) 内存占用50%(435/100*100%=43.5%) 阿里云监控内存大小转成实际占用内存大小,类似windows ,平均负载 0.1 差不多,其他几个参数,这里暂不介绍。

2.假设异常,找到异常的PID。

这里推荐 htop (清晰进程,线程, 命令行 ,排序支持鼠标双击,过滤,kill程序,标记某个线程或者进程,安装 apt-get install htop )

【深入浅出-VisualVM】(4): 分析CPU

如果你没有服务器上安装软件的权限的话,就老老实实用 top 。通过 top 命令(默认3秒刷新,回车空格手动刷新, top -d 5 5秒刷新,也可以进入top后输入 d 设置刷新时间, top -p 4360 监控指定进程),然后按X ,默认按照CPU%排序,查看系统运行情况,如果想强制按CPU 降序,则输入大写P,如果强制按内存降序,则输入大写M(top命令是交互式的)。

【深入浅出-VisualVM】(4): 分析CPU

解读:

1).现在系统时间 10:18.44 ,系统一直运行了 131天16小时51分,当前有1个用户登录系统(相同账号也算不同用户),平均负载分别为0.00,0.01,0.05(分别为1分钟,5分钟,15分钟的负载情况,load average是每隔5秒钟检查一次活跃的进程数,用特定的算法得到的数值,然后除以逻辑CPU数量,如果负载持续大于cpu个数,则表明负载过高) 。大概可以看出系统负载很低,运行状态健康。

2).当前一共有103个 进程 ,处于运行的有2个,处于休眠状态的有101个,处于停止状态的有0个,处于僵尸状态的有0个。大概可以看出系统进程总数较少,环境比较单纯,运行中的进程不多。

3). 0.3 us 用户空间占用CPU 0.3%, 0.7 sy 内核占用CPU 0.7%, 0.0 ni 改变过优先级的进程占用CPU的百分比, 98.0 id 空闲CPU的百分比为98.0 , 0.3 wa IO等待所占用CPU的百分比为0.3, 0.3 hi 硬中断(Hardware IRQ)占用CPU的百分比为0.3(外设给CPU的异步信号(中断),例如:网卡收到数据包), 0.0 si 软中断占用cpu的百分比为0(软件本身给操作系统内核的中断信号,通常由硬中断处理程序对操作系统内核的中断), 0.3 st 虚拟机被hypervisor偷去CPU的时间。

4). KiB Mem 代表内存占用, 1016272 total 内存总的大小1g(以kb为单位), 941492 used 使用中的内存总量为0.9g, 74780 free 空闲内存总量为74m(吓一跳吧,才74M,这个不是实际剩余的内内存大小) 115900 buffers 缓存的内存量为115m, 389836 cached cached大小380M。空闲内存总量只有74m,如果是windows去理解的话,此台服务器已经快挂了,实际内存大小等于74M+ buffers+cached = 580m(哈哈,够用,才占用一半呢), linux的内存管理和windows是不一样的,Linux会借用空闲的内存当作磁盘缓存, 磁盘数据缓存会让 linux 运行的更快,它永远不会从程序中拿出内存,它没有任何缺点,只是会混淆新手,如果你的应用程序需要更多的内存,他们会回收一部分用作磁盘数据缓存的物理内存,返回给应用程序,这个过程不需要启动交换,磁盘缓存(Disk caching)是不能禁用的, 但是可以释放磁盘缓存 1).只释放pagecache(文件缓存) echo 1 > /proc/sys/vm/drop_caches 2).释放dentries和inodes echo 2 > /proc/sys/vm/drop_caches 3).释放pagecache,dentries和inodes echo 3 > /proc/sys/vm/drop_caches
具体原理可以查看 linuxatemyram

我们利用 free 进一步证实上面的内容

【深入浅出-VisualVM】(4): 分析CPU 1).shared代表被线程共享的内存大小(大多数已经舍弃掉),buffer用来给块设备做缓存(记录文件系统的metadata和tracking in flight pages),cache缓存文件(第二次打开就很快),linux系统cached比较大,cached大小390m,buffers为110m。

2).435288代表 -buffers/cache ( 应用程序实际使用330m内存 ) 580984 代表 +buffers/cache( 实际剩余内存大小580m )。

3).重要等式 total = used + free used(-buffers/cache) = used(Mem)-buffers(Mem)-cached(Mem) free(+buffers/cache) = free(Mem) + buffers(Mem) +cached(Mem)

4). free 命令的值是从 /proc/meminfo 文件里读到的。

5).Swap 交换区 总共大小 0 kb,已经使用0kb,释放了0Kb, 如果swap used > 0,则可以说明系统内存瓶颈了

6).内存总和 free -t 总和等于total(Mem) + total(Swap)。

7).一般常用命令 free -s 3 每3秒观察一次内存使用情况。

占用cpu最高的进程是java,PID为28628,USER进程所有者root,PR优先级20,NI为0(负值优先级高,正值优先级低,PR=NI+20) ,VIRT进程使用虚拟内存1G(java进程最高只能占用到1G),RES进程实际使用的物理内存270M(不包含swap和shared),SHR共享内存大小5M,S进程状态随眠状态(S睡眠,R运行,T停止或被跟踪,Z僵尸,D不可中断睡眠态),%CPU占用CPU 0.7%,%MEM占用内存27%,TIME+进程使用cpu的时间54分40.12秒。总体看java进程运行良好。

3.这里假设PID为16368的 进程 占用CPU比较高(因为做了多次实验,所以PID没办法和上面的28628保持一致),

先用 ps -ef | grep java ,也可以用 htop filter java,也可以 jps -v 找到 java的进程ID 16368(只能查看当前用户的java pid,不太建议使用,-v显示详细信息,也可以不加)

【深入浅出-VisualVM】(4): 分析CPU 【深入浅出-VisualVM】(4): 分析CPU

?代表终端设备未知,Sl代表休眠状态多线程

Linux通过进程查看线程的方法 1). htop 按t(显示进程线程嵌套关系)和H(显示线程) ,然后F4过滤进程名。2). ps -eLf | grep java (快照,带线程命令,e是显示全部进程,L是显示线程,f全格式输出) 3). pstree -p <pid> (显示进程树,不加pid显示所有) 4). top -Hp <pid> (实时) 5). ps -T -p <pid> (快照) 推荐程度按数字从小到大

【深入浅出-VisualVM】(4): 分析CPU

4.利用 jstack 16368 > 2016-1-21.tdump (jstack是jdk自带的生成java stack和native stack的工具) 把threaddump输出到文件里,这里假设PID为16369(一般比进程号+1的是main线程,如果存在main线程貌似最先分配)的线程占用CPU最高,将其ID转成16进制0x3ff1(使用命令 printf "%x\n" 16369 输出3ff1)。

5.搜索threaddump文件,nid= 0x3ff1的线程堆栈,通过堆栈信息,就可以定位到占用CPU最高的代码地方(这里是正常的)。

【深入浅出-VisualVM】(4): 分析CPU

好啦,CPU冲高问题排查完毕,有了这样的知识体系,以后完全可以举一反三,coder君同时附上其他常用配合命令。

  • 每隔一秒显示新生代,老年代,持久代垃圾回收情况

    jstat -gcutil 16368 1000ms 参考 jstat -help ,也可以查看远程主机的GC情况,需要远程主机开启jstatd服务。

  • 观察堆内存情况

    jmap -dump:format=b,file=2016-1-21.mdump 16368 生成堆dump,放到mat或者vvm进行分析,上篇分析OOM有讲到。

  • 查看jvm系统参数

    jinfo 16368


以上所述就是小编给大家介绍的《【深入浅出-VisualVM】(4): 分析CPU》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

CSS权威指南(第三版)

CSS权威指南(第三版)

[美] Eric A.Meyer / 侯妍、尹志忠 / 中国电力出版社 / 2007-10 / 58.00

你是否既想获得丰富复杂的网页样式,同时又想节省时间和精力?本书为你展示了如何遵循CSS最新规范(CSS2和CSS2.1)将层叠样式表的方方面面应用于实践。 通过本书提供的诸多示例,你将了解如何做到仅在一处建立样式表就能创建或修改整个网站的外观,以及如何得到HTML力不能及的更丰富的表现效果。 资深CSS专家Eric A.Meyer。利用他独有的睿智和丰富的经验对属性、标记、标记属性和实......一起来看看 《CSS权威指南(第三版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换