Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >线上应用故障排查之一:高CPU占用

线上应用故障排查之一:高CPU占用

作者头像
爱撸猫的杰
发布于 2019-03-28 07:14:58
发布于 2019-03-28 07:14:58
1.4K0
举报
文章被收录于专栏:爱撸猫的杰爱撸猫的杰

一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环。

(友情提示:本博文章欢迎转载,但请注明出处:hankchen,http://www.blogjava.net/hankchen

以我们最近出现的一个实际故障为例,介绍怎么定位和解决这类问题。

根据top命令,发现PID为28555的Java进程占用CPU高达200%,出现故障。

通过ps aux | grep PID命令,可以进一步确定是tomcat进程出现了问题。但是,怎么定位到具体线程或者代码呢?

首先显示线程列表:

ps -mp pid -o THREAD,tid,time

找到了耗时最高的线程28802,占用CPU时间快两个小时了!

其次将需要的线程ID转换为16进制格式:

printf "%x\n" tid

最后打印线程的堆栈信息:

jstack pid |grep tid -A 30

找到出现问题的代码了!

现在来分析下具体的代码:ShortSocketIO.readBytes(ShortSocketIO.java:106)

ShortSocketIO是应用封装的一个用短连接Socket通信的工具类。readBytes函数的代码如下:

public byte[] readBytes(int length) throws IOException {

    if ((this.socket == null) || (!this.socket.isConnected())) {

        throw new IOException("++++ attempting to read from closed socket");

    }

    byte[] result = null;

    ByteArrayOutputStream bos = new ByteArrayOutputStream();

    if (this.recIndex >= length) {

           bos.write(this.recBuf, 0, length);

           byte[] newBuf = new byte[this.recBufSize];

           if (this.recIndex > length) {

               System.arraycopy(this.recBuf, length, newBuf, 0, this.recIndex - length);

           }

           this.recBuf = newBuf;

           this.recIndex -= length;

    } else {

           int totalread = length;

           if (this.recIndex > 0) {

                totalread -= this.recIndex;

                bos.write(this.recBuf, 0, this.recIndex);

                this.recBuf = new byte[this.recBufSize];

                this.recIndex = 0;

    }

    int readCount = 0;

while (totalread > 0) {

         if ((readCount = this.in.read(this.recBuf)) > 0) {

                if (totalread > readCount) {

                      bos.write(this.recBuf, 0, readCount);

                      this.recBuf = new byte[this.recBufSize];

                      this.recIndex = 0;

               } else {

                     bos.write(this.recBuf, 0, totalread);

                     byte[] newBuf = new byte[this.recBufSize];

                     System.arraycopy(this.recBuf, totalread, newBuf, 0, readCount - totalread);

                     this.recBuf = newBuf;

                     this.recIndex = (readCount - totalread);

             }

             totalread -= readCount;

        }

   }

}

问题就出在标红的代码部分。如果this.in.read()返回的数据小于等于0时,循环就一直进行下去了。而这种情况在网络拥塞的时候是可能发生的。

至于具体怎么修改就看业务逻辑应该怎么对待这种特殊情况了。

最后,总结下排查CPU故障的方法和技巧有哪些:

1、top命令:Linux命令。可以查看实时的CPU使用情况。也可以查看最近一段时间的CPU使用情况。

2、PS命令:Linux命令。强大的进程状态监控命令。可以查看进程以及进程中线程的当前CPU使用情况。属于当前状态的采样数据。

3、jstack:Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。

4、pstack:Linux命令。可以查看某个进程的当前线程栈运行情况。

解决方案

1. 排查应用是否创建了过多的线程

通过jstack确定应用创建了多少线程?超量创建的线程的堆栈信息是怎样的?谁创建了这些线程?一旦明确了这些问题,便很容易解决。

2. 调整操作系统线程数阈值 操作系统会限制进程允许创建的线程数,使用ulimit -u命令查看限制。某些服务器上此阈值设置的过小,比如1024。一旦应用创建超过1024个线程,就会遇到java.lang.OutOfMemoryError: unable to create new native thread问题。如果是这种情况,可以调大操作系统线程数阈值。 3. 增加机器内存 如果上述两项未能排除问题,可能是正常增长的业务确实需要更多内存来创建更多线程。如果是这种情况,增加机器内存。 4. 减小堆内存 一个老司机也经常忽略的非常重要的知识点:线程不在堆内存上创建,线程在堆内存之外的内存上创建。所以如果分配了堆内存之后只剩下很少的可用内存,依然可能遇到java.lang.OutOfMemoryError: unable to create new native thread。考虑如下场景:系统总内存6G,堆内存分配了5G,永久代512M。在这种情况下,JVM占用了5.5G内存,系统进程、其他用户进程和线程将共用剩下的0.5G内存,很有可能没有足够的可用内存创建新的线程。如果是这种情况,考虑减小堆内存。 5. 减少进程数 这和减小堆内存原理相似。考虑如下场景:系统总内存32G,java进程数5个,每个进程的堆内存6G。在这种情况下,java进程总共占用30G内存,仅剩下2G内存用于系统进程、其他用户进程和线程,很有可能没有足够的可用内存创建新的线程。如果是这种情况,考虑减少每台机器上的进程数。 6. 减小线程栈大小

线程会占用内存,如果每个线程都占用更多内存,整体上将消耗更多的内存。每个线程默认占用内存大小取决于JVM实现。可以利用-Xss参数限制线程内存大小,降低总内存消耗。例如,JVM默认每个线程占用1M内存,应用有500个线程,那么将消耗500M内存空间。如果实际上256K内存足够线程正常运行,配置-Xss256k,那么500个线程将只需要消耗125M内存。(注意,如果-Xss设置的过低,将会产生java.lang.StackOverflowError错误)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-11-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C语言】文件操作详解
如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件。
大耳朵土土垚
2024/03/13
1720
【C语言】文件操作详解
【重新认识C语言----文件管理篇】
在C语言编程中,文件操作是一个非常重要的部分。无论是读取配置文件、保存数据,还是处理日志文件,文件操作都是不可或缺的。C语言提供了一套丰富的库函数来进行文件的创建、打开、读取、写入和关闭等操作。本文将详细介绍C语言中的文件操作,帮助读者深入理解并掌握这些操作。
用户11456817
2025/02/08
1290
【C语言基础】:文件操作详解(后篇)
将字符写入流 将一个字符写入流并推进位置指示器。 字符被写入流的内部位置指示器所指示的位置,然后自动向前移动一个。
爱喝兽奶的熊孩子
2024/04/11
1990
【C语言基础】:文件操作详解(后篇)
【C语言篇】文件操作(下篇)
上面的四个都是针对字符的输入输出,但是实际文件会有不同的数据类型,这时就需要用到格式化输入输出函数了
半截诗
2024/10/09
970
【C语言篇】文件操作(下篇)
C语言-文件操作这一篇足够
上篇博客中我们写了通讯录的实现,但会有一个问题困扰着我们,就是说当这个程序结束之后,信息便也就丢失了,没有进行保存,这也不是我们想要的一个结果,我们希望在程序执行结束之后,下次再执行时,用户信息仍然在里面,这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据 库等方式。今天呢,我们就通过这篇博客来介绍文件操作的内容,把数据存储到磁盘文件当中去。
HABuo
2024/11/19
1120
C语言-文件操作这一篇足够
C语言进阶-文件操作超详解
scanf/printf、fscanf/fprintf、sscanf/sprintf函数对比
用户9645905
2022/11/30
1.1K0
C语言进阶-文件操作超详解
【C语言】看了这篇文章,如果你还不会文件操作的话,我把这篇文章给吃了(doge)
🚩write in front🚩    🔎大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎 🏅2021年度博客之星物联网与嵌入式开发TOP5~2021博客之星Top100~2021博客之星Top63~作者周榜84﹣作者总榜704~ 🆔本文由 謓泽 原创 CSDN首发🙉 如需转载还请通知⚠ 📝个人主页-謓泽的博客_CSDN博客 📃 📣系列专栏-【C】系列_謓泽的博客-CSDN博客🎓 ✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本📩 文件操作⇢目录 🚩wr
謓泽
2023/02/22
8830
【C语言】看了这篇文章,如果你还不会文件操作的话,我把这篇文章给吃了(doge)
C语言文件读写操作(详解)
文件是一段数据的集合,这些数据可以是有规则的,也可以是无序的集合。在stdio.h有一个非常重要的东西,文件指针,每个文件都会在内存中开辟一块空间,用于存放文件的相关信息,这些信息保存在一个结构体中: struct _iobuf { char *_ptr; //指向buffer中第一个未读的字节 int _cnt; //记录剩余的未读字节的个数 char *_base;//文件的缓冲 int _flag;//打开文件的属性 int _file;//获取文件描述 int _charbuf;//单字节的缓冲,即缓冲大小仅为1个字节 int _bufsiz;//记录这个缓冲大小 char *_tmpfname;//临时文件名 }; typedef struct _iobuf FILE; FILE是一个数据结构,用于访问一个流。每个流都会对应一个FILE结构体。
全栈程序员站长
2022/09/05
2K0
[c语言日寄]文件操作
在C语言的世界中,文件操作是一个不可或缺的技能。无论是数据的存储、读取还是处理,文件操作都扮演着关键的角色。从简单的文本文件到复杂的二进制文件,C语言提供了丰富的函数和工具来帮助我们高效地完成这些任务。今天,我们将深入探讨C语言中的文件操作,从基础的文件打开和关闭,到复杂的顺序读写和随机读写,再到文本文件和二进制文件的区别,以及文件缓冲区的使用。
siy2333
2025/04/01
850
C语言进阶——文件操作
  文件——是我们生活中必不可缺的一部分,优秀的文件管理能使我们工作效率更高,比如上学时的点名册、平时记账的手账本、电脑中存储数据的各种文件夹等。数据构成文件,文件成就数据,因此我们需要学习C语言中的各种文件操作,使数据能够做到持久化存储。
北 海
2023/07/01
3290
C语言进阶——文件操作
C语言文件操作
没错,这还是为了应付计算机二级的文件操作选择题方面,在程序题中好像也曾出现过。我做了简单的复习,希望到时候能通过。
布衣者
2021/09/07
2.8K0
C语言重点突破(六)文件操作
我们在前面的文章介绍了通讯录的程序,当通讯录运行起来的时候,可以给通讯录中增加、删除数据,此时数据是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受。 我们在想既然是通讯录就应该把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。 这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据库等方式。 使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
对编程一片赤诚的小吴
2024/01/23
1730
C语言重点突破(六)文件操作
C语言从入门到实战——文件操作
C语言中的文件操作是通过使用文件指针来实现的。可以使用标准库中的函数来打开、读取、写入和关闭文件。
鲜于言悠
2024/03/20
5510
C语言从入门到实战——文件操作
【Linux探索学习】第二十弹——基础IO:深入理解C语言文件I/O与Linux操作系统中的文件操作
https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482
GG Bond1
2024/12/10
1960
【Linux探索学习】第二十弹——基础IO:深入理解C语言文件I/O与Linux操作系统中的文件操作
C语言文件操作超详解
如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。
fhvyxyci
2024/09/24
1630
C语言文件操作超详解
C语言--文件操作教案
问题:当读取到文件末尾时,feof()会返回true,但此时已经读取了无效的EOF,导致循环多执行一次。
猫咪-9527
2025/03/27
2100
轻松拿捏C语言——【文件操作】
程序文件:包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows 环境后缀为.exe)
用户11162265
2024/06/14
1430
轻松拿捏C语言——【文件操作】
C语言文件操作:标准库与系统调用实践
1.考察fopen, fread, fwrite, fseek, fclose等函数的使用
用户11316056
2025/01/24
1780
C语言文件操作:标准库与系统调用实践
C 语言文件操作详解
在 C 语言中,文件操作是一个非常重要的主题。无论是保存用户数据、配置程序、还是读写日志文件,掌握文件操作都能使你的程序更加灵活和实用。本文将带你深入了解 C 语言中的文件操作,帮助你从基础到进阶,逐步掌握文件操作的技巧。
平凡之路.
2024/10/09
3550
C 语言文件操作详解
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 <stdio.h> 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
LuckiBit
2024/12/11
3310
【C语言】文件操作函数详解
推荐阅读
相关推荐
【C语言】文件操作详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档