优秀的编程知识分享平台

网站首页 > 技术文章 正文

记一次linux应用cpu%之后的分析(linux中cpu)

nanyue 2024-08-16 00:42:50 技术文章 8 ℃

由于近期我们公司的一个产品(C++),在投产之后每隔一两个月就会出现CPU%占用的问题,而且不会再降下来。

通过top -H -p [pid]查看是有两个线程占用都达到了98%,其他线程则正常。

这种情况如果是出现在测试环境,可以轻而易举的解决掉。因为测试环境可以随便使用命令查看堆栈信息等。但是由于投产的环境,

是禁止使用一些特殊命令,比如需要root权限的,比如使用之后影响应用程序服务的命令等,问题就变得很难。

在生产上使用top -H -p [pid] 查看cpu占用100%的线程,得到了线程id。但是之后又无从下手了。因为知道线程id后不知道该id对应哪个线程的代码。因为应用当中有很多类型的线程,分别负责不同的业务。

在得到这个生产问题之后,我进行了分析,得到以下两点优化点:

1)在日志中打印出线程id,这样下次出现cpu100%之后,通过线程id我可以找到出问题的线程了,然后就是分析这个线程在做什么事。

方法:(C++夸平台代码,支持win和linux系统)

//add by zyao @20190710 提供进程id和线程id获取方法

#ifdef WIN32

#define myPid() GetCurrentProcessId()

#define myTid() GetCurrentThreadId()

#else

#define myPid() getpid()

#define myTid() syscall(SYS_gettid)

#endif

经过定义以上预处理宏可以在线程中调用,然后打印出其值得到线程/进程id。以方便问题分析。

2)通过以上的方法我感觉还是麻烦,后来干脆就修改线程名称了。

应用当中开了很多类型的线程,每个线程负责其对应的业务,然后我通过查阅资料,看到prctl函数是可以设置线程名称的。

我只要将每个业务的线程名称设置为一个适当的值,然后在使用top -H -p [pid]查看线程的时候就可以直接看到那个业务的线程

cpu%了。

代码如下:(C++代码只写了linux下设置线程名称的方法)

#ifdef WIN32

#else

char buf[256] = { 0 };

sprintf(buf, "%s", "Recv");

if (strlen(buf) >= 0)

{

prctl(PR_SET_NAME, buf);

//pthread_setname_np(pthread_self(), buf); //glibc 2.12之后的版本中提供的接口

}

CKSConvertManager::GetInstance()->GetKSLog().WirteLog(__FILE__, __LINE__, "设置线程名称%s", buf);

#endif

由于我们生产服务器是运行在suse 11sp3上的,所以我只写了linux方法,我们的应用程序在windows上也能运行是跨平台的,但是在win上可以直接使用vs进行debug调试分析问题,所以无需修改线程名,故没有提供win上修改线程名称的方法。

经过以上两步改造,下次cpu100%将会能直接看到是那个业务线程出问题,然后再针对性的看代码。

当然,如果生产环境能用pstack等一些命令问题将会变得很简单,但问题是suse 11sp3生产环境压根没这命令,而且生产也不允许使用。

所以只能想其他办法慢慢分析。

当遇到cpu100%问题,当前的处理方法粗暴简单,那就是重启应用。

附:其他排查cpu100%方法(pstack生产机器没这个命令)

以多线程模块smsbu为例方法一:

第一步:查看smsbu进程ID

>>ps -ef | grep smsbu

可以看第二列显示的值便是进程ID。最后一列名称以smsbu打头的便是smsbu进程信息行。取该行的第二列数字即进程ID,举例进程id为:10228

第二步:查看进程id对应进程的线程信息

>>top -H -p 10228

可以得到进程各个线程的PID信息。即结果的第一列值。

同时可以得到各个线程占用cpu多少。找占用cpu100%的线程PID

第三步:获取线程号和线程PID对应关系

>>gdb - 10228

>>info threads

第一列id即为线程id,第四列类似(LWP 10228)中的10228即为线程pid。线程id=1的是父线程。通过PID找id

然后再继续输入

>>thread 5 (即关联线程号为5的线程)

>>bt (查看当前线程号的堆栈信息)

即可查看当前线程运行的堆栈信息。

通过堆栈信息分析,该线程运行情况,为何占用cpu过高

方法二:

第一步:查看cpu过高的进程ID。

>>top

第二步:将进程堆栈信息dump到文件中

gcore pid

第三步:将生成的core.XXXX文件取回来

第四步:在测试环境调试core文件

>>gdb bin.lexe core.xxxx (gdb [源程序] [core文件])

第五步:查看堆栈信息

步骤如方法一的第三步info threads往后 或者在gdb中使用thread apply all bt查看所有线程堆栈信息

最近发表
标签列表