前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >服务器CPU居高不下--解决问题历程

服务器CPU居高不下--解决问题历程

作者头像
付威
发布2018-12-05 14:28:05
8990
发布2018-12-05 14:28:05
举报

基本的概述

在一个服务器的集群上面,服务器的CPU长时间居高不下,响应的时间也一直很慢,即使扩容了服务器CPU的下降效果也不是很明显。

对于CPU过高的原因,可以总结到以下原因:

  • 太多的循环或者死循环
  • 加载了过多的数据,导致产生了很多的大对象
  • 产生了过多的对象,GC回收过于频繁(如:字符串拼接)

对于上面的情况,难点不是优化代码,难点在于定位到问题的所在,下面我们就用Dump抓包的方式来定位到问题的所在。介绍这个内容之前,我们要先回顾下.Net中垃圾回收的基础知识和一个工具的准备。


基础知识


垃圾回收触发条件
  • 代码显示调用System.GC的静态方法
  • windows报告低内存情况
  • CLR正在卸载AppDoamin
  • CLR正在关闭
大对象垃圾回收

CLR将对象分为大对象和小对象,认为大于85000字节或者更大的字节是大对象,CLR用不同的方式来对待大对象和小对象:

  • 大对象不是在小对象的地址空间分配,而是在进程地址空间和其他地方分配
  • GC不会压缩大对象,在内存中移动他们的代价过高,但这样会造成地址空间的碎片化,以至于会抛出OutOfMemeryException 异常。
  • 大对象总是在第二代回收。

工具准备

  1. 下载windbg文件
  2. 相关DLL准备clr.dll和sos.dll,(都在对应.Net版本安装目录下面,我的安装目录在C:\Windows\Microsoft.NET\Framework64\v4.0.30319)
  3. 一个cpu运行的较高的时期的DUMP文件(下面会说如何获取)
  4. 准备测试代码,此处为了演示方便,简单了写了一个有潜在问题的代码:
代码语言:javascript
复制
public  class Common
{
    public static List<string> GetList()
    {
        var list=new List<string>();
        for (int i = 0; i < 10000; i++)
        {
            list.Add(i.ToString());
        }
        return list;
    }


    public static string GetString(List<string> list)
    {
        var str = "";
        foreach (var l in list)
        {
            str += string.Format("'{0}',", l);
        }
        if (str.Length > 0)
        {
            str.Remove(str.Length - 1);
        }
        return str;
    }
}

我们知道在字符串的拼接的时候,每一个字符串都是一个对象,拼接后又产生了一个新对象,所以在GetString这个方法中会有大量的GC操作,下面我们就调用下这个代码,看下CPU的情况,为了模拟并发情况,我们开多个标签,每个标签每1s秒中刷新一次。

CPU
CPU

抓取Dump

在任务管理器中选择应用程序池对应的w3wp.exe,右击–>创建转储文件。创建完成后,会提示出指定的路径

taskManger
taskManger
taskManger
taskManger

根据上面的步骤,我们准备我们分析的文件如下:

dumpfile
dumpfile

分析Dump

  • 打开windbg,加载对应的dump文件
dumpOpen
dumpOpen
dumpOpen
dumpOpen
  • 配置Sysmbol,添加”cachec:\mysymbol;srvhttp://msdl.microsoft.com/download/symbols”
dumpOpen
dumpOpen
dumpOpen
dumpOpen
  • load sos.dll和clr.dll,命令如下: .load D:\windbg\sos.dll .load D:\windbg\clr.dll
  • 运行命令!threadpool 显示有关托管线程池的信息,其它一些SOS 调试扩展命令.
dumpOpen
dumpOpen
  • 运行!runaway 查询cpu占用时长比较长的几个线程Id
dumpOpen
dumpOpen
  • 运行~22s (进入线程查看),kb(查看对应的调用)
dumpOpen
dumpOpen
  • 运行~* kb 查看所有线程的堆栈调用
dumpOpen
dumpOpen
  • 在上面搜索GC和大对象出现的线程 (ctrl+f搜索:GarbageCollectGeneration和allocate_large_object )
dumpOpen
dumpOpen
  • 可以看到定位触发GC的线程是31号线程
  • 运行命令~31s 进入31线程,再运行!clrstack查看堆栈调用,最终可以定位到出问题的代码,是由于字符串的拼接导致大量的对象产生,从而触发了GC。
dumpOpen
dumpOpen

(本文完)

作者:老付 如果觉得对您有帮助,可以下方的订阅,或者选择右侧捐赠作者,如果有问题,请在捐赠后咨询,谢谢合作 如有任何知识产权、版权问题或理论错误,还请指正。 自由转载-非商用-非衍生-保持署名,请遵循:创意共享3.0许可证 交流请加群113249828: 点击加群 或发我邮件 laofu_online@163.com

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本的概述
  • 基础知识
    • 垃圾回收触发条件
      • 大对象垃圾回收
      • 工具准备
      • 抓取Dump
      • 分析Dump
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档