聊聊进程异常重启的问题------顺便详解linux句柄泄漏问题的定位(知识点: lsof -p xxx; ll /proc/xxx/fd)

来源:互联网 发布:九城软件电话 编辑:程序博客网 时间:2024/06/05 20:51

        之前做过嵌入式开发, linux环境玩代码, 这玩意儿最终是卖给用户。 产品一旦到用户手上, 要修复bug的代价就很大了, 而且, 由于是用户(个体)触发, 所以很多问题是不太好暴露出来的。 比如某些场景下的低概率core dump,  内存积累式泄漏, 句柄积累式泄漏。

        现在做互联网后台开发, 触发后台服务的是成千上万甚至是上亿的用户, 服务有什么问题, 很容易暴漏出来。 再低概率的core dump, 内存泄漏,句柄泄漏, 都会被成千上万的不同请求命中和触发。 所以, 很多时候, 在测试环境上OK的代码, 一放到外网真实环境, 就很容易出问题。  所以呢, 周五尽量不要发版本咯。

       

        来说说最近遇到的一个问题, 修改代码后, 灰度外网一台机器, 发现功能OK,  进程OK,  log也是OK,  于是以为万事大吉。 过了15分钟左右, 意外发现进程的时间变化了, oh my god, 第一反应是, 发生了core dump,  但是, 到对应目录下去看core文件, 发现没有。 难道是程序core dump后没有产生core ?   随后打开各种core开关, 没有发现任何与core dump相关的线索。

       正纳闷着, 屏幕上滚出很多提示, 大概提示是: check handle leak...  原来是资源泄漏了, 再看看最近改的代码, 果然是句柄没有关闭。 此时心想, 万幸有check handle leak的提示, 这是我们一个组件的提示。 原来, 组件检查到句柄泄漏到一定程度后, 为了提供持续服务, 重新拉取了进程, 所以, 进程时间就变了。


      上述找出句柄泄漏的过程很简单, 但依赖了组件提供的能力, 有很多时候, 我们并没有这样的提示, 那应该怎么思考呢?  

      有的同学可能说:遇到这种问题, 看代码的修改点就醒了。 我也认同这种看法, 但是, 有些时候, 很多人修改很多代码后, 才发现问题, 此时, 仅仅通过代码修改点来看, 无异于大海捞针。

      有的同学可能说:这种问题很好发现, 用coverity检查就知道了, 我也认同这种看法(实际上, 在老东家, 当时就是这么做的, 很有用, 很靠谱), 但是, 有些小公司根本买不起coverity等工具, 或者买了也不见得会落实使用。

      有的同学可能说: 你们代码review做得好烂, 我只想说, 呵呵。

      有的同学可能会有更好的解决方法.......


      下面,我假设发布代码之前, 审核者没有仔细review, 假设没有coverity检查, 假设查看代码修改记录也没法看清, 假设没有组件的check handle leak...提示, 那该如何着手尝试定位呢? 我的思路是:

      进程号变了, 必然是进程挂了, 被重新拉取了, 进程挂掉的原因很多: 比如程序core dump, 内存泄漏, 比如句柄泄漏, 比如权限问题......,  咱可以根据此思路来排查。

      在本例中, 打开了各种core开关, 进程重启的时候没有core, 基本可以先不考试是core dump引起的;

      查看进程占用内存, 发现内存比较稳定, 基本可以排除是内存泄漏;

      查看句柄使用情况, oh my god, 句柄的使用量在直线攀升,  看来, 就是你了!

      得意得意得意


       下面, 我来写个简单的代码demo来模拟当时的情景, 来定位句柄泄漏, 看代码:

#include <stdio.h>#include <fcntl.h>#include <unistd.h>int main(){printf("pid is %u\n", getpid());while(1){        int randNum = 0;        int fd = open("/dev/urandom", O_RDONLY);        if(-1 == fd)        {                printf("error\n");                return 1;        }        read(fd, (char *)&randNum, sizeof(int));printf("randNum is %d\n", randNum);sleep(1);}        return 0;}
     编译运行:

taoge@localhost Desktop> g++ main.cpp taoge@localhost Desktop> ./a.out pid is 6721randNum is -1429327421randNum is -212629638randNum is 1214302015randNum is 1541974428randNum is -2019951960randNum is -1962329827randNum is -492818638randNum is 1355048759
     
      不要停掉上述程序, 开启另外一个窗口:

taoge@localhost Desktop> lsof -p 6721COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF   NODE NAMEa.out   6721 taoge  cwd    DIR    8,2     4096 163966 /home/taoge/Desktopa.out   6721 taoge  rtd    DIR    8,2     4096      2 /a.out   6721 taoge  txt    REG    8,2     5574 158146 /home/taoge/Desktop/a.outa.out   6721 taoge  mem    REG    8,2   141492 158062 /lib/ld-2.12.soa.out   6721 taoge  mem    REG    8,2  1855584 158063 /lib/libc-2.12.soa.out   6721 taoge  mem    REG    8,2   202040 158071 /lib/libm-2.12.soa.out   6721 taoge  mem    REG    8,2   122232 134753 /lib/libgcc_s-4.4.4-20100726.so.1a.out   6721 taoge  mem    REG    8,2   942040   9544 /usr/lib/libstdc++.so.6.0.13a.out   6721 taoge    0u   CHR  136,1      0t0      4 /dev/pts/1a.out   6721 taoge    1u   CHR  136,1      0t0      4 /dev/pts/1a.out   6721 taoge    2u   CHR  136,1      0t0      4 /dev/pts/1a.out   6721 taoge    3r   CHR    1,9      0t0   3676 /dev/urandoma.out   6721 taoge    4r   CHR    1,9      0t0   3676 /dev/urandoma.out   6721 taoge    5r   CHR    1,9      0t0   3676 /dev/urandoma.out   6721 taoge    6r   CHR    1,9      0t0   3676 /dev/urandoma.out   6721 taoge    7r   CHR    1,9      0t0   3676 /dev/urandoma.out   6721 taoge    8r   CHR    1,9      0t0   3676 /dev/urandom
     可以看到, 进程打开了很多次/dev/urandom文件, 我们继续看:

taoge@localhost Desktop> ll /proc/6721/fd | wc -l85taoge@localhost Desktop> ll /proc/6721/fd | wc -l87taoge@localhost Desktop> ll /proc/6721/fd | wc -l88taoge@localhost Desktop> ll /proc/6721/fd | wc -l89taoge@localhost Desktop> ll /proc/6721/fd | wc -l90taoge@localhost Desktop> ll /proc/6721/fd | wc -l90taoge@localhost Desktop> ll /proc/6721/fd | wc -l91taoge@localhost Desktop> ll /proc/6721/fd | wc -l92taoge@localhost Desktop> ll /proc/6721/fd | wc -l93taoge@localhost Desktop> ll /proc/6721/fd | wc -l93taoge@localhost Desktop> ll /proc/6721/fd | wc -l94taoge@localhost Desktop> ll /proc/6721/fd | wc -l95taoge@localhost Desktop> ll /proc/6721/fd | wc -l95taoge@localhost Desktop> ll /proc/6721/fd | wc -l96taoge@localhost Desktop> ll /proc/6721/fd | wc -l96taoge@localhost Desktop> ll /proc/6721/fd | wc -l97taoge@localhost Desktop> ll /proc/6721/fd | wc -l98taoge@localhost Desktop> ll /proc/6721/fd | wc -l99taoge@localhost Desktop> ll /proc/6721/fd | wc -l100taoge@localhost Desktop> ll /proc/6721/fd | wc -l100taoge@localhost Desktop> ll /proc/6721/fd | wc -l101taoge@localhost Desktop> ll /proc/6721/fd | wc -l102taoge@localhost Desktop> ll /proc/6721/fdtotal 0lrwx------ 1 taoge taoge 64 Jul  1 18:37 0 -> /dev/pts/1lrwx------ 1 taoge taoge 64 Jul  1 18:37 1 -> /dev/pts/1lr-x------ 1 taoge taoge 64 Jul  1 18:37 10 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 100 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 101 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 102 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 103 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 104 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 11 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 12 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 13 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 14 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 15 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 16 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 17 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 18 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 19 -> /dev/urandomlrwx------ 1 taoge taoge 64 Jul  1 18:37 2 -> /dev/pts/1lr-x------ 1 taoge taoge 64 Jul  1 18:37 20 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 21 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 22 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 23 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 24 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 25 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 26 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 27 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 28 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 29 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 3 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 30 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 31 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 32 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 33 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 34 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 35 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 36 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 37 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 38 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 39 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 4 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 40 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 41 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 42 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 43 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 44 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 45 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 46 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 47 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 48 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 49 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 5 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 50 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 51 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 52 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 53 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 54 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 55 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 56 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 57 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 58 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 59 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 6 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 60 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 61 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 62 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 63 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 64 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 65 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 66 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 67 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 68 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 69 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 7 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 70 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 71 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 72 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 73 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 74 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 75 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 76 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 77 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 78 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 79 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 8 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 80 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 81 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 82 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 83 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 84 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 85 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 86 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 87 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 88 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 89 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:37 9 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 90 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 91 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 92 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 93 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 94 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 95 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 96 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 97 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 98 -> /dev/urandomlr-x------ 1 taoge taoge 64 Jul  1 18:38 99 -> /dev/urandomtaoge@localhost Desktop> 
       可以清晰地看到, 进程打开文件句柄(fd)的数量在不断增加, 原来果然是句柄在泄漏, 那怎么找到泄漏的代码所在的行呢? 直接在代码中搜索:/dev/urandom  就行了, 这样就知道了句柄泄漏的地方了。找到了问题, 解决起来就很简单了, 需要加上close(fd);


      OK, 再多说就是废话了, 就此打住。






        

       

1 0
原创粉丝点击