debug实战:进程Hang+High CPU
最近几周都在解决程序不稳定的问题,具体表现为程序(多进程)时不时的Hang住,同时伴随某个进程的High CPU。跟踪下来,基本都是各种死锁引起的。这里选取一个典型的场景进行分析。
1.抓dump分析
由于这个问题不能稳定重现,所以比较靠谱的方法是出现后抓Dump再分析。老方法:ProcDump -ma [ProcessName]。这是个多进程Hang住的情况,具体表现为主进程Main点击退出时,子进程Mkt不响应。到底是哪个进程挂掉了呢?
2.先看Main
首先!syncblk:
0:000> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
244 0000000023d99b68 5 1 0000000029b26bc0 100 41 0000000003c95a30 System.Object
41号线程持有object锁,MonitorHeld=5,持有者=1、等待者=2,所以有(5-1)/2=2个线程在等待这个锁。41号线程在干什么呢?为什么占着锁又不走下去呢?
/*0:000> !threads
ThreadCount: 974
UnstartedThread: 0
BackgroundThread: 965
PendingThread: 0
DeadThread: 8
Hosted Runtime: no
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
41 45 100 0000000029b26bc0 2b228 Preemptive 0000000000000000:0000000000000000 0000000002222bb0 1 MTA */
注意:这3个ID容易混淆,41是线程在windbg中的编号;45(ID)是线程在.net中的编号,对应vs调试时的托管ID;100(OSID)这个16进制ID的是操作系统给线程的唯一编号,对应于vs调试时的10进制ID,比如在这里是2560。
/*0:000> ~41e!clrstack
OS Thread Id: 0x100 (41)
Child SP IP Call Site
000000002780ea30 0000000077ab133a Microsoft.Win32.UnsafeNativeMethods.WriteFile(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)
000000002780ea30 000007fee5a775d2 Microsoft.Win32.UnsafeNativeMethods.WriteFile(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)
000000002780e9f0 000007fee5a775d2 DomainBoundILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)
000000002780eaf0 000007fee5af4aa0 System.IO.Pipes.PipeStream.WriteFileNative(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte[], Int32, Int32, System.Threading.NativeOverlapped*, Int32 ByRef)
000000002780eb40 000007fee5af4742 System.IO.Pipes.PipeStream.WriteCore(Byte[], Int32, Int32)*/
可以看到,41号线程卡在PipeStream.Write上面,MSDN上提到,如果Pipe的另一端不读完Write过去的byte[],Write就会一直阻塞:
Calling the PipeStream.Write() method blocks until count bytes are read or the end of the stream is reached.
也就是说,主进程Main在给子进程write,但子进程一直不收。
3.再看Mkt进程
同样!syncblk:
Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
42 0000000002358828 3 1 000000002063b9b0 34f8 17 0000000003909d28 System.Object
17号线程持有锁,另一个线程在等待。17号在干嘛?
/*OS Thread Id: 0x34f8 (17)
Child SP IP Call Site
0000000022c8b2f0 0000000077ab131a Microsoft.Win32.UnsafeNativeMethods.ReadFile(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)
0000000022c8b2f0 000007fee5a775d2 Microsoft.Win32.UnsafeNativeMethods.ReadFile(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)
0000000022c8b2b0 000007fee5a775d2 DomainBoundILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)
0000000022c8b3b0 000007fee5af4980 System.IO.Pipes.PipeStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte[], Int32, Int32, System.Threading.NativeOverlapped*, Int32 ByRef)
0000000022c8b400 000007fee5af44d4 System.IO.Pipes.PipeStream.ReadCore(Byte[], Int32, Int32)
0000000022c8b470 000007fe88a05852 IPC.PipeTransport.Send(Byte[])
0000000022c8b8a0 000007fe89f17b1f UI.WPF.WindowBase.UnRegisterAllIPCSubscriber()
0000000022c8b900 000007fe89f170df UI.WPF.WindowBase.WindowBase_Closed(System.Object, System.EventArgs)*/
看起来是在关闭Window的时候,17号线程拿到了锁,想要取消注册IPC却一直Read不到回复。再看是哪个线程在等锁,执行~*e!clrstack在输出里找Monitor.Enter这个函数,发现是8号线程在等锁:
/*0:000> ~8e!clrstack
Child SP IP Call Site
00000000211ae908 0000000077ab186a System.Threading.Monitor.Enter(System.Object)
00000000211aea00 000007fe89b09f06 UI.WPF.WindowBase.OnReciveIPCMessqage(MessageRoute.IMessage)*/
了解了锁的持有、等待关系之后,还是要回到代码上分析。从源码可知,Mkt的8号线程拿到锁之后要做的,就是Read Main进程Write过来的byte数组(这部分代码就不贴了)。而它之所以拿不到lock,是因为17号拿到了lock并给Main发消息要取消注册,并且在发完之后等Read。而Main的41号Write线程,却在等Mkt的8号线程Read。
private void UnRegisterAllIPCSubscriber()
{
lock (this)
{
_subscriber.Stop();
_ipcSubscribers.Clear();
}
}
4.小结
于是这样一个跨进程的死锁问题就发生了。问题的关键在于,上面这个取消注册的锁的范围太大了,_subscriber.Stop跨越了一次IPC调用,其实只有_ipcSubscribers是共享数据,缩小锁的范围就可以避免这个问题的发生。最后要感谢一下Tess Ferrandez,主要的思路来自她的这篇《A Hang Scenario, Locks and Critical Sections》。
debug实战:进程Hang+High CPU的更多相关文章
- linux上限制用户进程数、cpu占用率、内存使用率
限制进程CPU占用率的问题,给出了一个shell脚本代码如下: renice +10 `ps aux | awk '{ if ($3 > 0.8 && id -u $1 > ...
- 一次进程hang住问题分析。。。
这两天有同学使用数据校验工具时发现进程hang住了,也不知道什么原因,我简单看了看进程堆栈,问题虽然很简单,但能导致程序hang住,也一定不是小问题.简单说明下程序组件的结构,程序由两部分构成,dbc ...
- 查看进程,按内存从大到小 ,查看进程,按CPU利用率从大到小排序
查看进程,按内存从大到小 ps -e -o "%C : %p : %z : %a"|sort -k5 -nr 查看进程,按CPU利用率从大到小排序 ps -e -o "% ...
- Linux下如何查看哪些进程占用的CPU内存资源最多
linux下获取占用CPU资源最多的10个进程,可以使用如下命令组合: ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head linux下获取占用 ...
- linux:如何指定进程运行的CPU
coolshell最新的文章<性能调优攻略>在"多核CPU调优"章节,提到"我们不能任由操作系统负载均衡,因为我们自己更了解自己的程序,所以,我们可以手动地为 ...
- Nginx 关于进程数 与CPU核心数相等时,进程间切换的代价是最小的-- 绑定CPU核心
在阅读Nginx模块开发与架构模式一书时: "Nginx 上的进程数 与CPU核心数相等时(最好每个worker进程都绑定特定的CPU核心),进程间切换的代价是最小的;" &am ...
- [转] 指定进程运行的CPU
转自:https://www.cnblogs.com/liuhao/archive/2012/06/21/2558069.html coolshell最新的文章<性能调优攻略>在“多核CP ...
- [转] 多核CPU 查看进程分配的CPU具体核id
转自:https://linux.cn/article-6307-1.html ps. 方法二简明直接 done! 当你在 多核 NUMA 处理器上运行需要较高性能的 HPC(高性能计算)程序或非常消 ...
- 进程分析之CPU
进程分析之CPU 进程分析之CPU 本文转载自:https://github.com/ColZer/DigAndBuried/blob/master/system/cpu.md 在<进程分析之内 ...
随机推荐
- 2015苹果WWDC开发者大会
2015苹果WWDC开发者大会 (1)本届主题为“the epicenter of change(变革的中心)” (2)iOS 9.OS X.watchOS三款重要系统更新以及其他服务 (3)iOS ...
- Eclipse 设置文件的默认打开方式
web开发中,我们在编辑JSP/xml的时候,会碰到一个非常郁闷的事,直接双击打开的JSP页面,当我们在编辑的时候会到处跳,这个我是深有体会,所以我们就用右击 open with,但是久而久之我们会感 ...
- about shell
摘抄 cat 等 cat主要有三大功能:1.一次显示整个文件.$ cat filename2.从键盘创建一个文件.$ cat > filename只能创建新文件,不能编辑已有文件.3.将 ...
- mybatis动态sql中的trim标签的使用
trim标记是一个格式化的标记,可以完成set或者是where标记的功能,如下代码: 1. select * from user <trim prefix="WHERE" p ...
- Http简析
HTTP协议 属于应用层的面向对象的协议 HTTP协议的主要特点 支持C/S(客户/服务器)模式. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径.请求方法常用的有GET.HEAD.POST ...
- matlab cross 3*1 向量叉乘
一定是1*3 或者3*1 的向量才可以叉乘 A=[1 2 3] B=[4 5 6] cross(A,B) ans=[-3 6 -3] 解决机器人微分运动量之间的等价关系
- 如何编写跨平台的Java代码
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- Django开发博客- 三部曲
其实在django中实现一个功能只需要三个步骤即可,这里我姑且叫它三部曲. 这三部曲就是: 定义urls映射 定义views 定义templates 什么是URL? URL就算一个WEB地址,你在浏览 ...
- 工作日志 jquery slideDown slideUp
jquery里面使用 slideDown 和 slideUp会有一个像素的偏差
- 《javascript高级程序设计》第八章 The Browser Object Model
8.1 window 对象 8.1.1 全局作用域 8.1.2 窗口关系及框架 8.1.3 窗口位置 8.1.4 窗口大小 8.1.5 导航和打开窗口 8.1.6 间歇调用和超时调用 8.1.7 系统 ...