欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

性能监控/优化系列——内存/线程/锁相关

程序员文章站 2022-07-14 12:19:21
...

 1. 内存的分页(paging)、交换(swapping)、锁和线程的上下文切换(分为voluntary and involuntary context switching)需要监控。两种上下文的区别:voluntary ——voluntarily takes itself off the CPU;involuntary ——占用时间期满或优先级更高的线程取代。

2. 如果一个java程序或JVM在发生内存交换(swapping)表明有性能问题需要关注。
3. 当发现JVM的垃圾回收时间很长时,很可能是内存不足发生swapping。如果JVM运行在内存不足的机器上,它的内存堆可能会被交换出去,当做垃圾回收的时候需要遍历整个堆的内存,所以会要求处在磁盘中的数据给交换到内存,这个时候会产生很大的延迟,导致很多线程会停止运行。(一般情况下,当内存不够时,OS内核page scanner会去扫描内存,将那些不再使用的内存提供给需要的应用程序,如果不能找到足够的内存就会把最近最少被使用的内存page交换到磁盘。可获得的内存越少page scan rate就越高。
4. 从上面几点可以看出:当page scanner扫描的次数(Solaris下可以用vmstat,对应的列为‘sr)不为0(增多)且free内存有下降的趋势,那么交换swapping就会发生,性能就会开始下降。
Solaris下vmstat命令
kthr memory page disk faults cpu
r b w swap free re mf pi po fr de sr cd f0 s0 -- in sy cs us sy id
1 0 0 499792 154720 1 1697 0 0 0 0 0 0 0 0 12 811 612 1761 90 7 4
1 0 0 498856 44052 1 3214 0 0 0 0 0 0 0 0 12 1290 2185 3078 66 18 15
3 0 0 501188 17212 1 1400 2 2092 4911 0 37694 0 53 0 12 5262 3387 1485 52 27 21
1 0 0 500696 20344 26 2562 13 4265 7553 0 9220 0 66 0 12 1192 3007 2733 71 17 12
1 0 0 499976 20108 3 3146 24 3032 10009 0 10971 0 63 0 6 1346 1317 3358 78 15 7
1 0 0 743664 25908 61 1706 70 8882 10017 0 19866 0 78 0 52 1213 595 688 70 12 18
5. 关于锁,Java5之前的锁机制是直接代理了OS的锁元素(delegate Java monitor operations directly to operating system monitors, or mutex primitives),这样会提高system CPU utilization,因为system mutex primitives涉及到系统调用,也由于直接代理的因素需要OS级别的命令就可以查看到Java应用的锁竞争状况。但是,Java5之后有了变化,不再直接依赖OS的锁机制,而是在用户代码级别实现了锁逻辑,因此监控方法发生了变化。Java5的锁实现如下:spin in a tight loop trying to acquire a lock, if not successful after a number of tight loop spins, park the thread and wait to be notified when to try acquiring the lock again,也就是说,在一个循环中去获取锁,如果几次没有成功,那么就停止(parking)线程进行等待,直到被通知为止。
6. Java的锁竞争引起了线程上下文切换,CPU利用率很高,反过来讲,如果发现上下文切换过高,那么很可能是锁竞争导致的。The act of parking a thread along with awaking a thread results in an operating system voluntary context switch,从CPU时钟周期基本来讲,这是一个代价很高的操作,每个上下文交换需要80000以上个clock cycle。一般经验值:experiencing 5% or more of its available clock cycles in voluntary context switches(这个可以以1s时间周期为计算)很可能存在锁竞争。事实上,当该值达到3% to 5%就应该进行相关的排查工作。
7. 上述百分比的计算方法:如果一台机器的主频为3g,也就是30亿个时钟周期每秒,那么计算公式如下:Solaris——1s内上下文切换数*80000/30亿;Linux——1s内上下文切换数/虚拟处理器数*80000/30亿(为什么要除以虚拟处理器数:因为pidstat -w所统计的是所有处理的上下文切换数,每个处理器(核)都有自己的时钟,而Solaris中统计是平均每个核的上下文切换数,所以不需要在做除法)。
Solaris下mpstat命令
$ mpstat 5
CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl
0 4 0 1 479 357 8201 87 658 304 0 6376 86 4 0 10
1 3 0 1 107 3 8258 97 768 294 0 5526 85 4 0 10
CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl
0 0 0 0 551 379 8179 91 717 284 0 6225 85 5 0 10
1 2 0 0 2292 2 8247 120 715 428 0 7062 84 5 0 10
CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl
0 0 0 0 562 377 8007 98 700 276 0 6493 85 5 0 10
1 0 0 0 2550 4 8133 137 689 417 0 6627 86 4 0 11
CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl
0 0 0 0 544 378 7931 90 707 258 0 6609 87 5 0 8
1 0 0 0 2428 1 8061 125 704 409 0 6045 88 3 0 9
Linux下pidstat命令
$ pidstat -w -I -p 9391 5
Linux 2.6.24-server (payton) 07/10/2008
08:57:19 AM PID cswch/s nvcswch/s Command
08:57:26 AM 9391 3645 322 java
08:57:31 AM 9391 3512 292 java
08:57:36 AM 9391 3499 310 java
8. 常用命令:mpstat 3(Solaris)/pidstat -w -I -p 9391 5(linux版本2.6.23及以上
9.Java程序常用排查锁竞争问题的方法:periodically take thread dumps and look for threads that tend to be blocked on the same lock across several thread dumps。
10. 工具:Oracle Solaris Studio Performance Analyzer(Solaris和Linux)方便锁问题的排查,甚至它能够捕获到CPU缓存的miss率,另外常用的有jstack/pstack命令。
11. Involuntary上下文切换的暗示, High involuntary context switches表明有多于虚拟处理器数的轻量级进程准备去运行,这时伴随着高的运行队列和CPU利用率。优化方法:减少put到CPU的负载,增加CPU,优化数据结构和算法。还有一个可以操作的方法是:linux下使用taskset命令修改进程的“CPU亲和力”,也就是使用taskset充分利用多核CPU,让CPU的使用率均衡到每个cpu上。
12. 线程迁移,通常情况下,CPU调度器会将ready-to-run的线程放到它最后一次被执行的虚拟处理器上,如果该处理器繁忙,那么这个线程会被迁移到其他处理器上。这种线程迁移会影响到性能,因为线程所需要的数据可能在另外的虚拟处理器cache中不存在,故会产生stall延时。
Solaris上mpstat命令的migr”列监控线程是否发生了迁移。优化方法:creating processor sets and assigning Java applications to those processor sets,实际就是上面提到的taskset命令能够做的事情。经验值:在多处理器环境下,如果每秒大于500个迁移可以从“CPU亲和力”设置中获得较好的性能。