Linux Debugging(八): core真的那么难以追踪吗?
本周遇到了好几个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真的那么难以追踪吗?的更多相关文章
- Linux Debugging(五): coredump 分析入门
作为工作几年的老程序猿,肯定会遇到coredump,log severity设置的比较高,导致可用的log无法分析问题所在. 更悲剧的是,这个问题不好复现!所以现在你手头唯一的线索就是这个程序的尸体: ...
- 在Linux上利用core dump和GDB调试
段错误(segfault) "段错误"是程序试图操作不允许访问或试图访问的不允许内存的情况.可能导致段错误的原因主要有: 1.试图解引用空指针(你不允许访问内存地址0) 2.试图解 ...
- 在Linux上利用core dump和GDB调试segfault
时常会遇到段错误(segfault),调试非常费劲,除了单元测试和基本测试外,有些时候是在在线环境下,没有基本开发和测试工具,这就需要调试的技能.以前介绍过使用strace进行系统调试和追踪<l ...
- debian(kali Linux) 安装net Core
debian(kali Linux) 安装net Core curl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-previ ...
- linux下生成core dump文件方法及设置
linux下生成core dump文件方法及设置 from:http://www.cppblog.com/kongque/archive/2011/03/07/141262.html core ...
- 什么是core dump linux下用core和gdb查询出现"段错误"的地方
什么是core dump linux下用core和gdb查询出现"段错误"的地方 http://blog.chinaunix.net/uid-26833883-id-31932 ...
- linux下用core和gdb查询出现"段错误"的地方【转】
转自:http://blog.chinaunix.net/uid-30091091-id-5754288.html 原文地址:linux下用core和gdb查询出现"段错误"的地方 ...
- 发布项目到 Linux 上运行 Core 项目
发布项目到 Linux 上运行 Core 项目 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 ASP.Net Core 给我们带来的最大的亮点就是跨平台,我在我电脑(win ...
- Visual Studio 2017 通过SSH 调试Linux 上.NET Core
Visual Studio 2017 通过SSH 调试Linux 上.NET Core 应用程序. 本文环境 开发环境:Win10 x64 Visual Studio 2017 部署环境:Ubuntu ...
随机推荐
- 【BZOJ3110】【ZJOI2013】k大数查询
原题传送门 题意简析 给定一个区间,可以在这个区间上每个整数点插入若干个数(这些数数值可以重复)你需要支持2种操作: 1)在[a,b]间所有整数点插入c 2)查询[a,b]内第c大的数 解题思路 树套 ...
- ●BZOJ 2743 [HEOI2012]采花
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2743 题解: 树状数组,离线 求区间里面有多少种出现次数大于等于 2 的颜色. 类似某一个题 ...
- hdu 5131(2014 广州—模拟)
题意:给你n个人以及他们的杀人数.先按杀人数从大到小排名输出,然后是一些询问 一个人名,①输出杀人数比他大的人数和+1:②如果有人杀人数和他一样而且名字的字典序比他小,输出人数+1,没有则无视. #i ...
- 一个成功的 Git 分支模型(适用于商业应用开发)
在这篇文章中,我将推广一下大约一年前我介绍过的一些项目(公私皆有)中使用的开发模型,它们的结果都非常成功.有段时间我非常想写出来分享一下,但是我至今才抽出时间来.我不会言及任何项目细节,仅讨论分支策略 ...
- sqlserver 查询 inner join 同一表2次 只出一条查询结果
inner join T_MTN_MobileNumber k on 1=1 and k.hddm='01' inner join (select a.hdxx+','+b.hdxx as hdxx ...
- Kafka(转载)
Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cloudera.Apache Storm.Spa ...
- tensorflow共享变量 the difference between tf.Variable() and get_variable()
一般这样用tf.get_variable(): v = tf.get_variable(name, shape, dtype, initializer) 下面内容来源于 http://blog.csd ...
- 72. Edit Distance(困难,确实挺难的,但很经典,双序列DP问题)
Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...
- redis的基本数据类型
一:redis是一个开源的,使用C语言编写,支持网络,可基于内存亦可持久化的日志型,key-value方式存储的nosql数据库.作为缓存服务器,速度效率都很快,和memcache相似 redis支持 ...
- python学习之路网络编程篇(第四篇)
python学习之路网络编程篇(第四篇) 内容待补充