# 《UNIX 环境高级编程》笔记 - UNIX 基础知识

## UNIX 体系结构

从严格意义上说，可将操作系统定义为一种软件，它控制计算机硬件资源，提供程序运行环境。我们通常将这种软件称为 **内核**（kernel），因为它相对较小，而且位于环境的核心。

内核的接口被称为 **系统调用**（system call）。**公共函数库** 构建在系统调用接口之上，**应用程序** 既可以使用公共函数库，也可以使用系统调用。shell 是一个特殊的应用程序，为运行其它应用程序提供了一个接口。

```
+----------------------------+
|               Application  |
|    +---------+             |
|    |  Shell  |             |
|    |  +------+--------+    |
|    |  |  System Call  |    |
|    |  |  +--------+   |    |
|    +--|  | Kernel |   |    |
|    |  |  +--------+   |    |
|    |  +---------------+    |
|    |  Public Library  |    |
|    +------------------+    |
|                            |
+----------------------------+
```

从广义上说，操作系统包括了内核和一些其它软件，这些软件使得计算机能够发挥作用，并使计算机具有自己的特性。这里所说的其它软件包括系统实用程序（system utility）、应用程序、shell 以及公用函数库等。

例如，Linux 是 GNU 操作系统（比如 Ubuntu）使用的内核。

## 系统调用和库函数

所有的操作系统都提供多种服务的入口点，由程序向内核请求服务。各种版本的 UNIX 实现都提供良好定义、数量有限、直接进入内核的入口点，这些入口点被称为系统调用。

系统调用接口总是在《UNIX 程序员手册》的第 2 部分中说明，是用 C 语言定义的，与具体的 UNIX 实现技术无关。

UNIX 系统调用的使用方式是为每个系统在标准 C 库中设置一个具有相同名字的函数。用户进程用标准 C 函数的调用方式来调用这些函数，然后，这些函数会用系统所要求的技术来调用相应的内核服务。**从应用角度考虑，可将系统调用看作为 C 函数**。

《UNIX 程序员手册》的第 3 部分定义了程序员可以使用的公共函数库。虽然这些函数可能会调用一个或多个内核的系统调用，但是它们并不是内核的入口点。

**从实现角度来看，系统调用和库函数之间有着本质的区别**，但从应用角度来看，这些区别并不重要。如果可以的话，我们可以替换库函数，但是系统调用通常是不能被替换的。

以存储空间分配函数 `malloc` 为例。有多种方法可以进行存储空间分配，以及与其相关的无用空间的回收操作（最佳适应、首次适应等），并不存在对所有程序都是最优解的一种技术。UNIX 系统调用中处理存储空间分配的是 `sbrk(2)`，它不是一个通用的存储管理器。它按指定字节数增加或减少进程地址空间，如何管理该地址空间却取决于进程的具体行为。存储空间分配函数 `malloc(3)` 实现一种特定类型的分配，如果我们不喜欢其操作方式，则可以定义自己的 `malloc` 函数，但它很可能会使用 `sbrk` 系统调用。事实上，有很多软件包（例如 Redis 中可使用的 `jemalloc`）使用 `sbrk` 系统调用实现自己的存储空间分配算法。

内核中的 `sbrk` 系统调用分配一块空间给进程，而库函数 `malloc` 则在用户层次管理这一空间。

应用程序既可以调用系统调用，也可以调用库函数。很多库函数则会调用系统调用。

```
+---------------+                +------------------------+
| +-----------+ |                |          +-----------+ |
| |Application| |                |          |Application| |
| +-----------+ |                |          +-----------+ |
|    ^ ^ ^      |  User Process  | +---------+   ^        |
|    v v v      |                | |C Library|   |        |
|  +--------+   |                | +---------+   |        |
|  | malloc |   |                |     ^         |        |
|  +--------+   |                |     |         |        |
+---------------+                +-----|---------|--------+
      ^ ^ ^                            |         |
      | | |                            |         |
      v v v                            v         v
+---------------+                +------------------------+
|     |sbrk|    |                |                        |
|     +----+    |   Kernel       |      System Call       |
|               |                |                        |
+---------------+                +------------------------+
```

系统调用和库函数之间的另一个区别是：系统调用通常提供一种最小接口，而库函数通常提供比较复杂的功能。 从 `sbrk` 系统调用和 `malloc` 库函数之间的差别中可以看到这一点。比较不带缓冲的 I/O 函数和标准 I/O 函数时，也能看到这种差别。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.fantasticmao.cn/tech/c-and-unix/unix-like/unix-huan-jing-gao-ji-bian-cheng-bi-ji-unix-ji-chu-zhi-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
