# 延迟初始化

defer\_init，内核中的延迟满足

在上一节的内容中[page结构体，我要如何安放你的灵魂](/kernel-exploring/nei-cun-guan-li/00-memory_a_bottom_up_view/50-challenge_evolution/52-where_is_page_struct.md)中我们看到了为了应对海量内存，内核是如何安放page结构体的。然而到了这里，事情还没有结束。紧接着应对海量内存，内核遇到了另一个棘手的问题―初始化。

Page结构体需要初始化后才能加入到buddy分配器供内核中各个模块使用，可想而知，随着内存容量的增加，需要初始化的page结构体也会增加。如果没有记错的话，当内存达到T级别，page结构体初始化的时间将达到分钟级。

那有什么办法解决这个问题呢？有的，那就是

> 延迟满足

其实思想很简单，在系统启动时只初始化部分的page结构体，然后使用内核线程来初始化剩下的page结构体。从而达到尽量减少page结构体初始化对系统启动的影响。

多说无益，我们还是直接来看代码吧。

## 正常情况

为了有一个对比，我们先来看看没有defer\_init的情况。

```c
 start_kernel()
     setup_arch()
         x86_init.paging.pagetable_init() -> paging_init()
             sparse_init()
                 sparse_init_nid()
                     map = __populate_section_memmap()        (1)
                     sparse_init_one_section(sec, map)
             zone_sizes_init()
                 free_area_init() -> free_area_init_node()
                     free_area_init_core()
                         memmap_init() -> memmap_init_zone()
                             __init_single_page()             (2)
     mm_core_init()
         memblock_free_all()
             free_low_memory_core_early()
                 __free_memory_core() -> __free_pages_memory()
                     memblock_free_pages()
                         __free_pages_core()                  (3)
```

Page结构体要经历三个过程，被分配，被初始化，添加到buddy。

在上述代码片段中，分别标出了这三个步骤在正常情况下发生的时机。而defer\_init要解决的就是2,3在初始化时占用的时间过多，导致系统启动时间过长。

既然是在2,3的地方占用了太多时间，那么就把这部分的工作延后执行把。

## 延迟满足

现在我们来看看内核代码是如何把这部分的工作延后执行的。

```c
 start_kernel()
     setup_arch()
         x86_init.paging.pagetable_init() -> paging_init()
             sparse_init()
                 sparse_init_nid()
                     map = __populate_section_memmap()
                     sparse_init_one_section(sec, map)
             zone_sizes_init()
                 free_area_init() -> free_area_init_node()
                     free_area_init_core()
                         memmap_init() -> memmap_init_zone()
                             defer_init()                     (1)
                             __init_single_page()
     mm_core_init() -> mem_init()
         memblock_free_all()
             free_low_memory_core_early()
                 __free_memory_core() -> __free_pages_memory()
                     memblock_free_pages()
                         early_page_uninitialised()           (2)
                         __free_pages_core()
     rest_init()
         pid = kernel_thread(kernel_init, NULL, CLONE_FS);
             kernel_init_freeable() -> page_alloc_init_late()
                 deferred_init_memmap()                       (3)
```

在上面的代码片段中可以看到，在1，2的地方分别增加了判断，是否要跳过这部分的初始化。

接着在3的位置启用了一个内核线程来初始化剩下的page结构体，并将page释放到buddy system。

好了，这件事情就是这么简单～


---

# 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://richardweiyang-2.gitbook.io/kernel-exploring/nei-cun-guan-li/00-memory_a_bottom_up_view/50-challenge_evolution/54-defer_init.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.
