本周遇到了好几个core都很有典型性。在这里和大家分享下。

相信有过Linux编程经验的人,肯定都遇到过。感觉周围人很多对core有天然的恐惧感,尤其对刚入行不久的同学来说。当然了,也有工作好几年看到core也束手无策的。今天就分析一下,core,其实大部分都是很容易解决的。如果一个core很难以复现,那么说明还是很复杂的,算是Corner case,可能需要很长时间,脑子里要有很好的运行时状态才可以(阅读源码,学习的是逻辑;将源码对应到运行时的状态,分析一些状态机的转换,再去分析可能会发生的情况)。相信前几篇文章会对这种Corner case的分析与解决打下比较好的基础。

相反,那种每次必现,或者复现比率非常高的case,是非常容易解决的。

多线程必然出core?

如果是你新加入的代码引入的core,实际上非常容易解决的,简单的对比一下修改的diff,然后看一下是否有比较低级的错误。如果发现不了,看是否是多线程的问题?单线程如果没有出core,改成多线程就出core,那么就说明多线程竞争某些变量了:同时修改某些变量导致出问题。这个时候你可能第一反应会加锁。我本人非常反感加锁;即使你加锁的粒度很小,作用域也够小,但是只要是加锁,就代表有阻塞,就代表维护起来会很麻烦。这些共享变量真的那么值得加锁吗?可否换成局部变量?如果他是一块动态内存,为了调用某个接口时不要频繁申请释放内存(比如这个接口每秒几千次的调用),那么初始化时候申请一块内存是绝对合理的:请把它设置为线程变量吧。每个线程初始化时候申请这块内存。

当然了你如果实现的是一个框架或者架构调用的接口,这个接口要做到线程安全的。那么看起来你并不能控制这个线程什么时候启动;线程数目会是多少个,那么就没有办法了吗?

实际上,方法有很多,比如,你可以在一个map中维护一个“线程”变量的对应关系

__gnu_cxx::hash_map< pid_t, void *> thread_data_map;
void * thread_buffer;
std::map<pid_t, void *>::iterator it;
lock
it = thread_data_map.find(pid);
if (it == thread_data_map.end()) {
//init "thread data"
thread_data_map[pid] = create_buffer();
} else {
thread_buffer = it->second;
}
unlock

这里不得不使用了一个锁。实际上由于线程数是有限的,因此这个效率还好。我本周实现了一个qps可以达到2000+的在线应用,基本上锁的代价在整个的call stack中可以忽略不计。

当然了,比较好的框架可能会提供OnThreadInit这种接口,那么在这边申请线程变量吧:

int pthread_setspecific (pthread_key_t key, const void *value);

在实现逻辑的函数获取该变量即可:

void *pthread_getspecific (pthread_key_t key);

什么时候要使用线程变量?看多线程下是否对该变量有写操作,如果有就要申请线程变量(或者加锁),否则必然出core。

不要给自己埋下一个坑:

今天一个同学的core看起来是做了一个“优化”,节省了申请变量的时间。

void init() {
my_struct * some_var;
...
some_var->res = new some_res;
some_var->res->set_value1(some_common_value1);
some_var->res->set_value2(some_common_value2);
} void * thread_func(my_struct * some_var) { some_var->res->set_value3(value_3);
...
}

set_value3就是一个出core的原因。这个也是一个典型的多线程必然出core的case。实际上,res没必要提前申请吧。把它改成一个局部变量,性能几乎没有的损耗。当然了,如果这个资源很大,那么就当成线程变量吧。

那么如何分析core?

实际上,上述的场景出现的core如果仅从core本身,可能一时不好排查问题出在哪里;而且core的位置可能还不一样,不可避免的出现替罪羊;比如调用第三方的模块,实际上是自己的全局变量导致到了第三方的调用栈时出core了。因此一定要排查自己的处理是否正确。

确定调用的接口是否线程安全;如果是你的同事,你得确定他说的是对的。就像今天又另外的一个core,调用者坚称他写的是线程安全的,仿佛不是线程安全的就像是代码写的不好似得;最后排查出他写的代码不是线程安全时,他问你什么是线程安全的。

那么回答一下,如何分析core?

首先了解清楚core出现的应用场景,比如长句子处理会有core;多线程处理会有core;特殊字符会有core;这个QA会给你一个比较清楚的说明。然后通过core的call stack去大概确定大概的源码位置。

源码面前,了无秘密。

你读源码,它展现的是逻辑;但是你脑中,要有个runtime的运行时调用栈,多线程的调度;天马行空。

当然了,还是解决不了,开始从core得到更详细的信息吧!看看调用栈的参数是什么,切换一个线程看看其他的几个线程的frame是什么。

还解决不了?

那么它是Corner case,只要把应用在core后立即启动就行了。记得EMC有个bug的选项是unable to root cause, 形容的很贴切。同时不要忘记自我安慰:码的码多了,肯定有bug,谁能保证服务100%呢?

Linux Debugging(八): core真的那么难以追踪吗?的更多相关文章

  1. Linux Debugging(五): coredump 分析入门

    作为工作几年的老程序猿,肯定会遇到coredump,log severity设置的比较高,导致可用的log无法分析问题所在. 更悲剧的是,这个问题不好复现!所以现在你手头唯一的线索就是这个程序的尸体: ...

  2. 在Linux上利用core dump和GDB调试

    段错误(segfault) "段错误"是程序试图操作不允许访问或试图访问的不允许内存的情况.可能导致段错误的原因主要有: 1.试图解引用空指针(你不允许访问内存地址0) 2.试图解 ...

  3. 在Linux上利用core dump和GDB调试segfault

    时常会遇到段错误(segfault),调试非常费劲,除了单元测试和基本测试外,有些时候是在在线环境下,没有基本开发和测试工具,这就需要调试的技能.以前介绍过使用strace进行系统调试和追踪<l ...

  4. debian(kali Linux) 安装net Core

    debian(kali Linux) 安装net Core curl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-previ ...

  5. linux下生成core dump文件方法及设置

    linux下生成core dump文件方法及设置    from:http://www.cppblog.com/kongque/archive/2011/03/07/141262.html core ...

  6. 什么是core dump linux下用core和gdb查询出现"段错误"的地方

    什么是core dump   linux下用core和gdb查询出现"段错误"的地方 http://blog.chinaunix.net/uid-26833883-id-31932 ...

  7. linux下用core和gdb查询出现"段错误"的地方【转】

    转自:http://blog.chinaunix.net/uid-30091091-id-5754288.html 原文地址:linux下用core和gdb查询出现"段错误"的地方 ...

  8. 发布项目到 Linux 上运行 Core 项目

    发布项目到 Linux 上运行 Core 项目 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 ASP.Net Core 给我们带来的最大的亮点就是跨平台,我在我电脑(win ...

  9. Visual Studio 2017 通过SSH 调试Linux 上.NET Core

    Visual Studio 2017 通过SSH 调试Linux 上.NET Core 应用程序. 本文环境 开发环境:Win10 x64 Visual Studio 2017 部署环境:Ubuntu ...

随机推荐

  1. Codeforces 343E Pumping Stations

    Description 题面 题目大意:求一个排列 \(P\),使得 \(\sum_{i=1}^{n-1}maxflow(P_i,P_{i+1})\) 尽量大 Solution 构造出最小割树,那么第 ...

  2. 【NOIP2016】天天爱跑步

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...

  3. 51 nod 1188 最大公约数之和 V2

    1188 最大公约数之和 V2 题目来源: UVA 基准时间限制:2 秒 空间限制:262144 KB 分值: 160 难度:6级算法题   给出一个数N,输出小于等于N的所有数,两两之间的最大公约数 ...

  4. uva 10118(DP)

    UVA 10118 题意: 有4堆糖果,每堆有n(最多40)个,有一个篮子,最多装5个糖果,我们每次只能从某一堆糖果里拿出一个糖果, 如果篮子里有两个相同的糖果,那么就可以把这两个(一对)糖果放进自己 ...

  5. 5-15 QQ帐户的申请与登陆 (25分) HASH

    实现QQ新帐户申请和老帐户登陆的简化版功能.最大挑战是:据说现在的QQ号码已经有10位数了. 输入格式: 输入首先给出一个正整数NN(\le 10^5≤10​5​​),随后给出NN行指令.每行指令的格 ...

  6. 《Java技术》第一次作业

    (一)学习总结 1.在java中通过Scanner类完成控制台的输入,查阅JDK帮助文档,Scanner类实现基本数据输入的方法是什么?不能只用文字描述,一定要写代码,通过具体实例加以说明. (1)使 ...

  7. Quartz + Tablesaw 报表统计

    场景 在12 月份做的报表功能中,直接从 ES 查询一个月的数据.当数据量特别大时,查询速度会非常缓慢甚至查询失败.解决方案是使用定时任务,在每天凌晨指定时间自动查询前一天的数据,然后写入 CSV 文 ...

  8. 值得珍藏的HTTP协议详解

    转自:http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html 引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式 ...

  9. Hibernate 自动生产表

    hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. 今天就来演示一下Hibernate最初级的 ...

  10. aways on 配置部署(二)——配置域

    前一篇中我们基本了解了配置aways on的三个步骤,本篇就具体讲解如何配置域. DNS的配置 上篇可以看到三台服务器的ip地址,网关,DNS等配置,其中sqlDNS服务器的dns为自己的ip地址,s ...