深入解析Mac OS X & iOS 操作系统 学习笔记(六)

进程跟踪和调试

DTrace

DTrace中的“D”指的是D语言。这是一门完整的跟踪语言,通过这门语言可以创建专门的跟踪器(tracer)或者探测器(probe)

druss 工具是一个底层为DTrac的工具,允许跟踪系统调用时打印出C风格的形式,显示系统调用、参数及返回值。druss支持3种使用模式:

  • 通过druss 允许一个进程:在druss 的参数后面指定命令参数
  • 附加到某个正在允许的进程示例:在druss -p 参数指定进程的PID
  • 附加到命名的进程:在druss -n 参数指定进程的名字

druss 的另一个有用的特性是能够自动锁定子进程(指定 -f 参数)
druss 还可以同时当场跟踪器和剖析器使用

进程信息

除了DTrace 之外,OS X 还提供了两个关键机制可以查看详细的进程信息

  • sysctl:sysctl 提供了一些显示进程统计数据的变量
  • proc_info:OS X 和 iOS 都提供了proc_info 系统调用。通过proc_info 可以查询进程和线程的很多信息

进程和系统快照

除了 DTrace 和 Instruments 之外,在 OS X 中还有一些工具能够获得系统或进程状态的“快照”(snapshot)

  • system_profiler( ):图形工具
  • sysdiagnose( ):是一个一站式的完美诊断工具
  • allmemory( ):捕获用户进程的所有内存使用情况
  • stackshot( ):可以获得进程执行状态的快照
  • *stack_sanpshot系统调用:这个系统调用的参数是pid、一个返回快照的缓冲区、缓冲区大小以及一些参数。这个快照机制的实现细节会深入到Mach微内核中

kdebug

kdebug 是內建内核跟踪设施。默认是禁用的
OS X 提供了3个利用kdebug 设施的工具

  • sc_usage:显示每一个进程的系统调用信息
  • fs_usage:显示系统调用,但是显示的是与文件、套接字和目录相关的应用。可以显示系统范围内的跟踪(除非调用时提供了PID 或 命令参数)
  • latency:显示中断和调度的延迟值。这个工具展示落在阈值内的上下文切换和中断处理程序技术,这两个分别可以通过-st 和 -it 参数设置

应用程序崩溃

大部分应用程序都可能会崩溃。在UNIX 中,崩溃和一个信号有关。崩溃的真正原因来自于内核,内核发现进程无法继续执行时,生成这个信号作为最后的补救方法

  • 核心转储:当一个进程崩溃时,可以选择是否生成核心转储文件。这取决于进程的资源限制RLIMIT_CORE的设置。默认情况下是禁止的
  • Crash Reporter:iOS 和 OS X 都没有选择创建巨大的核心转储文件,而是包含一个Crash Reporter,当进程异常终止(崩溃)时自动触发Crash Reporter生成详细的崩溃日志,保存在用户的Library/Logs/CrashReporter目录下或者系统的Library/Logs/CrashReporter目录下
  • 修改Crash Repoerter 选项:如果安装了Xcode,那么可以在 /Developer/Application/Utilities 目录下找到一个名为CrashReporter的小程序。启动程序
  • defaults( ):将DialogType 属性修改为basic、developer 或 server

内存破坏的bug

内存破坏是程序中常见的bug来源。应用程序崩溃的主要原因就是缓冲区溢出(既包含栈也包含堆)和堆内存的破坏。问题在于,在很多情况下,导致问题的代码和出现问题的代码相隔甚远,因此从出现bug到引发崩溃之间肯呢个会间隔数分钟甚至更长时间

  • LibC中的内存保护:OS X 的LibC库高度可配置,malloc( ) 的手册页记录了可以控制内存分配行为的环境变量,如下表
环境变量 用途
MallocLogFile 设置malloc调试日志文件
MallocCheckHeapStart
MallocCheckHeapEach
MallocCheckHeapSleep/Abort
在MallocCheckHeapStart 次分配后,每隔MallocCheckHeapEach 次分配之后检查堆的一致性。如果发现堆不一致的情况,要么进入睡眠(允许调试),要么调用abort( )(通过SIGABRT 崩溃)
MallocErrorAbort
MallocCorruptionAbort
发送任何错误时调用abort( )(即发送 SIGABRT 信号),或只有内存破坏时调用abort( )
MallocGuardEdges
MallocDoNotProtectPrelude
MallocDoNotProtectPostlude
在分配的大内存块之前(如果没有设置MallocDoNotProtectPrelude)和之后(如果没有设置MallocDoNotProtectPostlude)添加守护页
MallocScribble 在分配的内存中填满0xAA,在释放的内存中填满0x55
MallocStackLogging
MallocStackLoggingNoCompact
MallocStackLoggingDirectory
将malloc操作时所用的栈跟踪记录到/tmp(或 MallocStackLoggingDirectory 指定的目录)中。然后可以调用 leaks( ) 和 malloc_history( ) 之类的程序,后者要求设置MallocStackLoggingNoCompact

LibGMalloc:OS X 还提供了一个特殊的库libgmalloc.dylib,这个库可以截获并调试分配内存。这个强大的库的工作原理是截获LibSystem 中的分配函数,一旦挂上了目标函数,就可以很容易地将其替换为更复杂的替代品,从而对内存分配施加更多的限制,以期能够捕捉到导致崩溃的蛛丝马迹
具体来说,libgmalloc库提供了以下的技术

  • 给么一个分配的内存块加上自定义的数据头,其中包含了关于分配详情的调试信息:这个数据头记录了分配时的线程ID 和 栈回溯,还带有一个常量值(魔数)0xDEADBEEF,这个常量值可以用于检测同一个缓冲区分配和解除分配的错误。
  • 将内存块分配在自己专有的页面上,将相邻的页面设置为不可写(如果设置了MALLOC_ALLOW_READS),或者设置为完全不可访问:分配的内存块也放在其所在页面的尾部(除非设置了MALLOC_PROTECT_BEFORE)。这样做的结果就是任何读/写操作如果越过了缓冲区的尾部就会导致读写操作越过页边界,从而导致越过未处理的页错误,使得进程收到总线错误的信号(SIGBUS)而崩溃。设置MALLOC_PROTECT_BEFORE 环境变量会将这个保护行为翻转过来,即保护缓冲区之前不能被访问,而不是保护缓冲区后面
    -释放内存块时接触分配页面:在free( ) 释放内存块同时解除分配其所在页,这样的话,如果在释放的缓冲区上进行读写操作会导致总线错误

自动发生总线错误表示存在页面处理的 bug,一旦发生,就使得调试变得相对简单。将 gdb 附加到进程上,可以定位崩溃的位置,然后检查这个自定义的数据头,判断分配相关的问题,最后修复问题:要么修改缓冲区分配的参数。要么移除出错的操作

内存泄露

另外一个常见的bug 就是内存泄露。当程序员分配了内存或某个对象,但是忘记调用free( )释放内存或调用delete 删除对象时,就会发生能吃泄露。内存泄露的问题很难查找,因为内存泄露不会导致致命的bug 。而是慢慢地填满进程内存空间,因为一旦一个指针丢失了,在程序运行时,就再也无法回收这个指针指向的内存了。
Xcode 的 Instruments 工具提供了针对跟着内存分配和泄露的工具(如下图)

为内存调试而设计的Instruments 的界面.png
  • heap( ):列出给定进程的堆中所有分配的缓冲区,使用很简单,只要传入PID或部分进程的名字即可。这个工具可以识别类的名字,所以对Objective-C 编译的二进制文件和依赖 CoreFundation 的库非常有用
  • leaks( ):遍历进程的堆,检查可疑的内存泄露,对进程进行采样,生成一个分配但是没有释放的指针的报告
  • malloc_history( ):malloc_history( ) 工具提供了进程中发生的每一次内存分配的详细数据,包括dyld( ) 进行的那些初始内存分配,要求设置 MallocStackLogging 和 MallocStackLoggingNoCompact 环境变量

标准 UNIX 工具

  • **ps( ) **:可以显示进程列表
  • top( ) 系统全局视图:获取当前系统运行状况的关键工具
  • 通过lsof( ) 和 fuser( ) 进行文件诊断:lsof( ) 显示一个进程所有文件描述符(包括套接字)的映射; fuser( ) 提供一个反向的映射,从文件到用于这个文件的进程。主要作用的诊断文件锁定或者“文件被占用”的问题
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容