TASK_ZOMBIE
  当一个进程调用exit()系统调用退出后,它的父进程应该知道该进程的终止。处于TASK_ZOMBIE状态的进程会等待其父进程通知其释放所有的数据结构。


  图1-6 进程状态

  僵尸进程
  当一个进程接收到一个信号而终止,它在结束自己之前,通常需要一些时间来结束所有的任务(例如关闭打开的文件)。在这个通常非常短暂的时间内,该进程是一个僵尸进程。
  进程已经完成所有的关闭任务后,它会向父进程报告其即将终止。有些时候,一个僵尸进程不能把自己终止,这将会引导它的状态显示为z(zombie)。
  使用kill命令来关闭这样的一个进程是不可能的,因为该进程已经被认为已经死掉了。如果你不能清除僵尸进程,你可以结束其父进程,然后僵尸进程也随之消失。但是,如果父进程为init进程,你不能结束它。init进程是一个非常重要的进程,因此可能需要重启系统来清除僵尸进程。
  1.1.8 进程内存段
  进程使用其自身的内存区域来执行工作。工作的变化根据情况和进程的使用而决定。进程可以拥有不同的工作量特性和不同的数据大小需求。进程必须处理各种数据大小。为了满足需求,Linux内核为每个进程使用动态申请内存的机制。进程内存分配的数据结构如图1-7所示。


  图1-7 进程地址空间

  进程内存区由以下几部分组成:
  Text段
  该区域用于存储运行代码。
  Data段
  数据段包括三个区域。
  – Data:该区域存储已被初始化的数据,如静态变量。
  – BSS:该区域存储初始化为0的数据。数据被初始化为0。
  – Heap:该区域用于根据需求使用malloc()动态申请的内存。堆向高地址方向增长。
  Stack段
  该区域用于存储局部变量、函数参数和返回函数的地址。栈向低地址方向增长。
  用户进程的地址空间内存分布可以使用pmap命令来查看。你可以使用ps命令来查看内存段的大小。可以参阅2.3.10的“pmap”,“ps和pstree”。
  1.1.9 Linux CPU调度
  任何的计算机的基本功能都非常简单,是计算。为了能够计算,它意味着必须管理计算资源或处理器和计算任务,也是我们所知道的线程或进程。感谢Ingo Molnar的巨大贡献,Linux内核使用一个O(1)的算法代替以前的O(n)的CPU调度算法。O(1)指的是一种静态的算法,意味着选择一个进程并执行所花费的时间是一个常数,不管进程的数量的大小。
  新的调度算法的扩展性非常好,不管进程的数量或者处理器的数量是多少,系统的开销都是非常少的。该算法使用两个进程优先级数组:
  active(活动的)
  expired(过期的)
  调度器根据进程的优先级和优先拦截率为进程分配时间片,然后进程以优先级顺序放置到active数组内。当进程时间片耗尽,进程申请一个新的时间片并放置到expired数组内。当active数组中的所有进程的时间片耗尽,这两个数组进行切换,重新运行该算法。对于一般的交互式进程(相对于实时进程),拥有高优先级的进程通常比低优先级的进程得到更长的时间片和更多的计算时间,但这并不表示低优先级的进程会被完全忽略(饿死)。该算法的优势是为拥有大量线程和进程并拥有多处理器的企业级环境提升Linux内核的扩展性。该O(1)的新CPU调度器是为内存2.6设计的,但是现在已经移植到2.4系列中。图1-8说明了Linux CPU如何调度工作。


  图1-8 Linux内核2.6 O(1)调度器

  新调度器的另一个显著改进是支持非一致性内存架构(NUMA)和对称多线程处理器,例如Intel超线程技术。
  改进后的NUMA支持确保只有某个节点过载时,负载平衡才会跨越某个NUMA节点。这个机制确保了在NUMA系统相对比较缓慢的扩展链接流量的小化。尽管每个调度节拍时负载平衡会遍历调度域群组中的处理器,但只有在节点过载并请求负载平衡时,负载才会跨越调度域转移。


  图1-9 O(1)CPU调度器结构