Skip to content
Go back

程序、线程和进程

Edit page

程序映像

当程序运行时,操作系统会将可执行模块复制到一个内存块中,这个在内存中运行的实例被称为程序映像 (Program Image)

1. 内存分区

程序映像的内存通常被划分为不同的逻辑分区(段),主要包括:

  • 程序文本/代码段 : 存储机器代码指令,通常位于低位内存区。
  • 数据段 :
    • 已初始化的静态变量和全局变量。
    • 未初始化的静态变量和全局变量(BSS 段,在程序执行前由系统初始化为 0)。
  • 栈区 (Stack): 存储函数调用的活动记录(包括局部变量、函数参数、返回地址等)。
  • 堆区 (Heap): 存储通过动态内存分配(如 malloccalloc 等)分配的空间。
  • 其他空间: 包含命令行参数(argc, argv)以及环境变量的空间。

2. C语言数组初始化特性

  • 部分初始化规则: 在 C 语言中,一旦你显式地初始化了数组的一部分元素,剩余的所有未显式赋值的元素都会被编译器自动初始化为 0
    • 例如: int arr[5] = {1, 2}; 会被初始化为 [1, 2, 0, 0, 0]

3. 静态变量与线程安全

  • 线程不安全 (Not Thread-Safe): 静态变量(在整个程序生命周期内共享同一个内存地址)会使得在多线程环境下执行的程序变得极不安全。
  • 如果一个函数内部使用了静态变量,当多个线程同时调用该函数并修改该变量时,会产生数据竞争。
  • 除非在受控的情况下(例如使用了互斥锁 Mutex 等同步机制),否则在多线程编程中应尽量避免使用静态变量

4. 虚拟内存与物理内存映射

  • 连续假象: 对程序而言,程序映像看起来像是占用了一个完美的、连续的虚拟内存块。
  • 物理不连续: 实际上,操作系统底层通过内存管理单元 (MMU) 将其映射到不连续的物理内存中。
  • 分页机制 (Paging): 常见的映射方式是将程序映像分割成大小相同的“片”,称为页 (Pages)。当处理器需要引用某一页的内存时,会通过查询操作系统的页表 (Page Table) 来查找该页在物理内存中的真实位置。

Unix 程序中的错误处理与调试

1. 错误处理标准方法

在 Unix/Linux 系统编程中,处理错误通常遵循以下三种标准方法:

  1. 致命错误终止: 直接在 main 函数中(或通过 exit()/abort())打印错误消息,并退出程序。
  2. 设置 errno (最常见): 函数在发生错误时返回特定的错误标志(如 -1NULL),并由系统或底层库自动设置全局变量 errno,以指示具体的错误类型。
  3. 返回错误代码: 某些库或函数(如 POSIX 线程库 Pthreads)不使用 errno,而是直接将错误代码作为函数的返回值返回。

2. 调试信息处理技巧

  • 条件编译 : 处理调试打印信息(如 printf 或日志记录)的最佳实践是:不要在代码里到处硬编码打印语句,而是将其包裹在条件编译模块中(例如使用宏 #ifdef DEBUG#endif)。
  • 优势: 这样可以在开发阶段通过定义宏来激活大量的调试输出;而在发布生产版本时,只需取消宏定义,编译器就会自动忽略这些打印语句,从而保证程序的运行效率和日志的整洁。

Edit page