2018-08-30 16:34:38 wwxxlld 阅读数 80
  • Android内存泄漏案例分析

    Android内存泄漏案例分析视频教程,该课程结合一个真实案例,来演示Android内存泄露问题,从发现到分析定位,再到最终解决的全过程。一款优秀的Android应用,不仅要有完善的功能,也要有良好的体验,而性能是影响体验的一个重要因素。内存泄露是Android开发中常见的性能问题。

    11247 人正在学习 去看看 CSDN讲师

 

利用top以及valgrind命令去查找测试,

1.利用valgrind命令。这个命令大概是这样使用的: valgrind --tool=memcheck --show-reachable=yes ./a.out  

然后可以得到一个这样的东西:

/*
==2741== 
==2741== ERROR SUMMARY: 1173925 errors from 285 contexts (suppressed: 35 from 1)
==2741== malloc/free: in use at exit: 359,172 bytes in 1,584 blocks.
==2741== malloc/free: 4,058 allocs, 2,474 frees, 31,717,527 bytes allocated.
==2741== For counts of detected errors, rerun with: -v
==2741== searching for pointers to 1,584 not-freed blocks.
==2741== checked 1,886,784 bytes.
==2741== 
==2741== LEAK SUMMARY:
==2741==    definitely lost: 1,392 bytes in 2 blocks.
==2741==      possibly lost: 15,812 bytes in 512 blocks.
==2741==    still reachable: 341,968 bytes in 1,070 blocks.
==2741==         suppressed: 0 bytes in 0 blocks.
==2741== Use --leak-check=full to see details of leaked memory.
*/

可以大概的知道开辟了多少空间,释放了多少,丢失了多少等信息,比较直观的反应出来

2.利用top命令: top | grep a.out

自己写一个测试程序a.out,while(1)循环调用需要测试的函数,得到的界面大概这样的

看如图所示红框内,程序在运行期间内存不断在上涨,基本上可以判断该函数存在内存泄漏,建议大家实际测试时,如果这一项内存增长不是很快速的的话,测试时间长一点,一天,一周甚至更长,将该命令执行结果重定向到一个文件里,如果重定向到文件,top命令需要加上-b参数,否则文件会乱码,建议加上-d参数设定一个时间,单位是秒 ,

例:top -b -d 10 | grep a.out  >> top.txt ,10秒钟执行一次该命令,并将结果重定向到top.txt中。

至于找内存泄漏点就比较简单了,从后往前注释代码,编译再去看内存泄漏情况。

2019-07-08 11:49:14 mo4776 阅读数 125
  • Android内存泄漏案例分析

    Android内存泄漏案例分析视频教程,该课程结合一个真实案例,来演示Android内存泄露问题,从发现到分析定位,再到最终解决的全过程。一款优秀的Android应用,不仅要有完善的功能,也要有良好的体验,而性能是影响体验的一个重要因素。内存泄露是Android开发中常见的性能问题。

    11247 人正在学习 去看看 CSDN讲师

总结几种linux下观察程序使用资源情况的工具,包括:CPU,内存,fd有无泄漏,IO有无异常(比如日志异常输出),网络IO有无异常。通过这几种工具监控程序运行时资源有无异常,让程序更加稳定。

CPU使用率

最常用的命令是top,它可以显示整个系统中所有进程的CPU使用情况并且可以进行排序,当然它不止可以监控CPU资源,还可以监控内存,IO等。默认以CPU的使用率排序。最简单的方式就是直接输入top命令查看整个系统资源使用情况。

通过top命令也可以监控进程中线程CPU的使用情况,默认也是按CPU使用情况排序

-H 是一个很有用的参数,可以直接查看进程中线程资源使用的情况,并且可以看到进程中线程数

top -H -p 18047

如上命令通过top查看进程18047所有线程的资源使用状态,如下是结果

top - 14:56:53 up 28 days,  4:12,  3 users,  load average: 0.00, 0.03, 0.05
Threads:  15 total,   0 running,  15 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.9 us,  0.3 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  7747244 total,  1567056 free,  2786128 used,  3394060 buff/cache
KiB Swap:  7995388 total,  7646984 free,   348404 used.  4241380 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                     
18047 root      20   0  366744  21036   2464 S  0.0  0.3   0:07.73 RelayServer                                                                                                 
18051 root      20   0  366744  21036   2464 S  0.0  0.3   0:03.08 RelayServer                                                                                                 
18052 root      20   0  366744  21036   2464 S  0.0  0.3   0:00.00 RelayServer                                                                                                 
18053 root      20   0  366744  21036   2464 S  0.0  0.3   0:17.26 RelayServer                                                                                                 
18054 root      20   0  366744  21036   2464 S  0.0  0.3   0:26.31 RelayServer                                                                                                 
18055 root      20   0  366744  21036   2464 S  0.0  0.3   0:09.40 RelayServer                                                                                                 
18056 root      20   0  366744  21036   2464 S  0.0  0.3   0:11.53 RelayServer                                                                                                 
18057 root      20   0  366744  21036   2464 S  0.0  0.3   0:04.05 RelayServer                                                                                                 
18058 root      20   0  366744  21036   2464 S  0.0  0.3   0:24.14 RelayServer                                                                                                 
18059 root      20   0  366744  21036   2464 S  0.0  0.3   0:17.90 RelayServer                                                                                                 
18060 root      20   0  366744  21036   2464 S  0.0  0.3   0:38.72 RelayServer                                                                                                 
18061 root      20   0  366744  21036   2464 S  0.0  0.3   0:22.37 RelayServer                                                                                                 
18062 root      20   0  366744  21036   2464 S  0.0  0.3   0:42.98 RelayServer                                                                                                 
18063 root      20   0  366744  21036   2464 S  0.0  0.3   0:14.47 RelayServer                                                                                                 
18064 root      20   0  366744  21036   2464 S  0.0  0.3   1:56.67 RelayServer

软中断

linux中的软中断包括网络收发,定时,RCU锁等各种
,每个CPU都对应一个软中断内核线程,名字是ksoftirqd/CPU编号。当软中断事件的频率过高时,内核线程也会因为CPU使用率过高而导致软中断处理不及时,进而引发网络收发,调度缓慢等性能问题。

可以通过 watch -d cat /proc/softirqs 命令查看系统软中断次数,其中watch命令是变化,cat /proc/softirqs才是显示系统中真正的累计中断次数

一种分析网络服务的收发包是否正常的方式:通过查看软中断中NET_TX 和 NET_RX的增速是否很快,如果很快,CPU在处理大量网络中断,使用率肯定会增高。这个时候就需要查看程序收发包的代码逻辑,为什么会有大量的收发包情况。

如下命令输出,显示每个CPU上软中断的累计次数

Every 2.0s: cat /proc/softirqs                                                                                                                                                                                   Tue Jul  2 17:36:50 2019

                    CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
          HI:          2          0          0          0          0          0          2          0
       TIMER:    3010721    2977489    3016155    3099307    2897057    3492281    2896383    2853132
      NET_TX:       6201         43         69        201        914       1233        336         82
      NET_RX:     897297     336229     907668   16233407    8454552     506387     877685   16687073
       BLOCK:       4227        416     158020        147        158      65584        104    1391370
BLOCK_IOPOLL:          0          0          0          0          0          0          0          0
     TASKLET:       3797        169        207        157    7311978       2827        668   15754714
       SCHED:    1307215     474968     706726     330146     550114     258509     535334     326909
     HRTIMER:          0          0          0          0          0          0          0          0
         RCU:    1864254    1629223    1880544    1730405    1864998    1876487    1865292    1806708
         

在网络程序的协议设计中应尽量避免设计成小包协议(避免收发大量小包),这种情况会造成产生大量的的收发包中断,而影响性能

句柄泄漏

句柄泄漏是服务端编程经常遇到问题,这种问题的表现比较隐晦,它并不影响业务,但是如果服务长时间运行或在请求高峰值的情况下,句柄泄漏加剧,达到进程限制值。这个时候服务就无法处理新的请求了。所以在服务测试阶段就应该测试服务有无句柄泄漏的情况。

lsof -p 进程id

lsof列出了进行所有的资源,常见的包括文件fd,socket fd,eventfd,timerfd,eventpoll等,通过lsof命令可以查看指定进程打开的fd,根据linux下一切皆文件的思想

watch lsof -p 进程id

可以查看指定进程的fd的变化情况,判断出fd是否有泄漏。

COMMAND     PID USER   FD      TYPE   DEVICE SIZE/OFF      NODE NAME
RelayServ 18047 root  cwd       DIR    253,0     4096   3070583 /usr/local/smartseesip/siprelay
RelayServ 18047 root  rtd       DIR    253,0     4096       192 /
RelayServ 18047 root  txt       REG    253,0  7921129   3070563 /usr/local/smartseesip/siprelay/RelayServer
RelayServ 18047 root  mem       REG    253,0  2107816 201329626 /usr/lib64/libc-2.17.so
RelayServ 18047 root  mem       REG    253,0    88720 201326793 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
RelayServ 18047 root  mem       REG    253,0  1141552 201329666 /usr/lib64/libm-2.17.so
RelayServ 18047 root  mem       REG    253,0   995840 201329703 /usr/lib64/libstdc++.so.6.0.19
RelayServ 18047 root  mem       REG    253,0   110808 201329686 /usr/lib64/libresolv-2.17.so
RelayServ 18047 root  mem       REG    253,0    19512 201329664 /usr/lib64/libdl-2.17.so
RelayServ 18047 root  mem       REG    253,0   142296 201329684 /usr/lib64/libpthread-2.17.so
RelayServ 18047 root  mem       REG    253,0    44088 201329688 /usr/lib64/librt-2.17.so
RelayServ 18047 root  mem       REG    253,0   164432 201329619 /usr/lib64/ld-2.17.so
RelayServ 18047 root    0r      CHR      1,3      0t0      1028 /dev/null
RelayServ 18047 root    1w      CHR      1,3      0t0      1028 /dev/null
RelayServ 18047 root    2w      CHR      1,3      0t0      1028 /dev/null
RelayServ 18047 root    3w      REG    253,0        0 137585576 /usr/local/smartseesip/siprelay/relay/relay.20190702-000220.18047.log
RelayServ 18047 root    4r     FIFO      0,8      0t0  12209677 pipe
RelayServ 18047 root    5w     FIFO      0,8      0t0  12209677 pipe
RelayServ 18047 root    6r     FIFO      0,8      0t0  12209678 pipe
RelayServ 18047 root    7w     FIFO      0,8      0t0  12209678 pipe
RelayServ 18047 root    8u     IPv4 12209679      0t0       UDP 192.168.100.104:sentinel-lm 
RelayServ 18047 root    9u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   10u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   11u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   12u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   13u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   14u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   15u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   16u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   17u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   19u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   20u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   21u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   23u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   24u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   25u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   26u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   27u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   28u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   31u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   32u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   33u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   36u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   37u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   38u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   41u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   42u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   43u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   46u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   47u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   48u  a_inode      0,9        0      6765 [timerfd]

如上所示,lsof列出了RelayServer所打开的所有句柄,包括socket fd,文件,event fd,timer fd等

IO

服务的业务模型通常分为CPU密集型和IO密集型,CPU密集型就是服务需要占用CPU进行大量计算,比如视频转码服务,会议服务等。IO密集型是主要业务操作是IO操作,比如ftp服务,代理服务等。CPU密集型的服务CPU占用比较高,IO密集型服务CPU占用比较低(当然高低是个相对概念)。

top 命令的输出中有个wa占用比例可以用来判断当前系统的IO情况,如果服务是CPU密集型,这个wa占用率高,那么就应该要注意了,比如需要关注是否是在狂打日志。

top中iowait的比例

通过 pidstat -d 来查看每个进程的IO情况,确定具体进程的IO情况,如果所关注的进程出现异常值(值比预期的大),那么就需要检查进程的代码逻辑了


[root@localhost GWStreamServer]# pidstat -d 5
Linux 3.10.0-327.el7.x86_64 (localhost.localdomain)     2019年07月02日  _x86_64_        (4 CPU)

21时52分11秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
21时52分16秒     0      1321      0.00      4.79      0.00  dmserver

21时52分16秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
21时52分21秒     0      1321      0.00      4.00      0.00  dmserver
21时52分21秒     0      2879      0.00      0.80      0.00  slapd
21时52分21秒     0      2881      0.00      2.40      0.00  java
21时52分21秒     0      3009      0.00      5.60      0.00  java
21时52分21秒     0      3036      0.00      2.40      0.00  java

网络

最常用的命令就是netstat,可以查看程序占用的端口及端口被哪个程序占用,可以查看tcp的状态,可以统计当前系统的网络协议信息

  • 查看RelayServer的占用的端口
netstat -anp | grep RelayServer 

输出如下,RelayServer占用udp端口 5093

udp        0      0 192.168.20.87:5093      0.0.0.0:*                           2841/./RelayServer
  • 查看端口554被哪个程序占用
nestat -anp | grep 554

输出如下,554被DarwnStreamin程序占用,类型为tcp,状态为listen

tcp        0      0 0.0.0.0:554             0.0.0.0:*               LISTEN      2688/DarwinStreamin
  • 协议状态统计
netstat -s 

可以统计协议的工作状态,但它的输出较多,不便宜观察,推荐使用

ss -s 

输出如下:

Total: 508 (kernel 625)
TCP:   80 (estab 51, closed 6, orphaned 0, synrecv 0, timewait 5/0), ports 0

Transport Total     IP        IPv6
*         625       -         -        
RAW       1         0         1        
UDP       14        10        4        
TCP       74        40        34       
INET      89        50        39       
FRAG      0         0         0        

TCP那行里,可以直接看到当前系统所有tcp连接的状态,如已连接状态,close状态等。这样的输出数据简洁明亮,便于观察。

程序调试

  • top + gdb,在前面介绍过通过 top -H -p 命令可以查看指定进程中,线程占用的资源情况。比如观察到占 CPU最高的线程ID后,我们可以通过gdb - pid 直接附加到线程,查看当前线程的堆栈信息,定位程序逻辑问题。

  • perf top,一般在生产环境是不可能用gdb直接去调试程序,这样会造成程序无法处理业务。通过perf工具,可以直接查看系统中消耗性能最大的函数列表。

top + gdb的方式,简单,直接。perf工具提供的分析方式更多,更深入,当然也要求对linux系统知识有更深的理解。

没有更多推荐了,返回首页