分类: LINUX
2013-05-24 00:59:43
1 资源消耗有cpu消耗、文件io、网络io、以及内存的消耗,当某一个资源到达极限时,那么性能也就会达到瓶颈,必须通过分析找出瓶颈点。
2 cpu消耗
诊断方法有top可以查看load、cpu利用率和分布、线程、内存等宏观情况,还可以使用vmstat,可以更加直观的看到上下文切换的频率,还有内存、io等更加详细的信息。cpu消耗主要分布在us、sy、wa、hi,wa是io等待造成的。
当sy过高时,可能说明线程开太多,有较多的上线文切换。几个因素可以加剧上下文切换,例如线程进入io阻塞挂起、线程竞争锁失败挂起、线程调用sleep等。可以通过jstack dump(或者kill -3)调用堆栈来看到底是哪些线程在等待锁,找出锁竞争激烈的代码。
当hi过大则可能说明,硬件中断较多,例如网卡频繁接收到数据。
当us特别高时,说明有用户线程进行大量的计算,那么最好是找到那个us使用较大的线程id,转化成16进制,然后jstack dump调用堆栈,搜索到那个线程,就可以定位到问题了。us高也有可能是频繁gc、或者full gc,这种情况就要看是否有内存泄露,应该及时释放无用对象的引用。如果程序没有问题,那么应该调整jvm的内存配置。
3 文件io消耗
通过vmstat可以看到内存的free\swap\cache\buffer的情况,其中cache是用来进行缓存的,只有在写文件或者第一次读文件的时候才会产生真正的io,操作系统内核会把常用的文件缓存到内核内存中。
通过pidstat -d -t -p[pid]可以跟踪到线程的io消耗情况。定位到高消耗的线程id后,通过jstack找到具体的io消耗代码。
通过iostat也可以查看到每一个设备的历史io状况。
4 网络io消耗
用sar命令来分析操作系统的网络io消耗状况。当网络io消耗过大的时候,依然只能通过jstack来找到大量进行发送、接收字节流的代码咯
5 内存消耗分析
通过jmap\vmstat\mat\visualvm来分析内存消耗。
一般来说会将xms和xmx设置为一样,避免在运行时动态增长内存。
只有在创建线程和使用direct bytebuffer才会操作堆外的内存,所以在内存消耗方面最值得关注的还是jvm自己的内存。
分析内存要看swap和物理内存的消耗情况。通过vmstat可以看到swpd\buffer\free\cache\si\so等数据。swpd是指虚拟内存已用的部分;buffer是指用于缓冲的内存;cache是用于缓存的内存;free表示空闲的物理内存;si表示每秒从disk读入到内存的数据量;so是指从每秒内存刷到disk的数据量。
当swpd过高的时候,表示物理内存不够用了,so把数据从内存中刷到磁盘,以便腾出空间给当前的运行程序使用。当程序变化的时候,会从disk中读入数据到内存,以便恢复程序的运行,这个过程会产生swap io,当swap io发生得比较严重的时候,会影响系统性能。
当物理内存消耗过大的时候,一般是jvm的内存设置过大,或者创建过多线程、或者是用direct buffer放了太多对象。
通过sar -r可以查看内存的消耗。kbmemfree\kbmemused分别表示物理内存free和使用的数据量;kbswapfee/kbswapused分别表示swap的空闲和使用数据量;当物理内存有空闲时,为了提高系统性能,还会有一部分用来buffer和cache,所以可以认为物理内存=kbmemfree+kbmemused+kbbuffer+kbcache。
sar的缺点是不能看到进程所消耗的内存,而top可以查看,top看的的java进程内存使用包括了jvm已分配的内存加上jvm外部的物理内存。所以根据top也判断不出jvm内部消耗的内存有多少,因为无法知道jvm已分配的内存(只知道《xmx)。
6 内存调优
根据系统的实际运行情况,gc情况,对象存活特点来配置xms\xmx\xmn\newperm\maxperm\Survivor\maxTenuringThreshold(一般来说是15)。
目标是尽可能让对象在新生代被回收,减少minor gc频率,避免full gc。
http://developer.51cto.com/art/200907/135160.htm
7 具体方案
us过高,那么可以剔除死循环代码,或者让线程间歇sleep。
sy过高,减少线程数量、减少锁竞争。
io消耗过高,异步写文件(log4j),批量读写文件,限流,限制文件大小,进可能用缓冲区。
网络消耗过高,同理限流。
内存消耗过高,释放不必要的引用,使用对象池,采用合理的缓存失效算法;使用弱引用,对象会在full gc时被回收;使用软引用,对象会在内存不够用的时候回收
8 锁竞争
尽量使用并发包的类。
使用Treiber,实现无阻塞stack。
使用Micheal-scott非阻塞队列算法,例子ConcurrentLinkedQueue。
尽量不用锁。
拆分锁,锁粒度细化,例如ConcurrentHashMap。
读多写少,copy on write。
9 分析命令总结
top,查看全局cpu、内存,-H 查看线程,running可以查看到处于就绪队列的线程数。VIRT(虚拟内存) RES(物理内存) SHR(贡献内存)
vmstat查看全局的cpu、物理内存、swap、中断、上下文切换、io,并可以周期采样
sar也是可以查看全局的信息,同时还可以查看历史的信息。
pidstat除了查看全局信息外,还可以查看具体某一个进程的信息,提供更加细粒度的分析方式。用他来分析每个java线程的资源消耗情况,定位到资源消耗最大的线程id,转换成16进制,再结合jstack就可以定位到具体的java代码。
http://www.cnitblog.com/tjitty/archive/2010/07/12/67429.html
http://www.cnblogs.com/bangerlee/articles/2555307.html
10 btrace.....