当前位置:首页>Linux>《Linux-0.12 源码篇》- 05 内存管理

《Linux-0.12 源码篇》- 05 内存管理

  • 2026-07-01 16:11:01
《Linux-0.12 源码篇》- 05 内存管理

字数 6241,阅读大约需 32 分钟

第五章:内存管理

内存是计算机系统中最宝贵的资源之一。Linux 0.12的内存管理系统负责将有限的物理内存分配给多个进程使用,同时通过分页机制和虚拟内存技术,让每个进程都感觉自己独占了整个地址空间。这套系统包括物理内存管理、虚拟内存映射、页面分配回收、写时复制机制以及页面交换等关键技术,是操作系统实现进程隔离和内存保护的基础。

5.1 内存布局与地址空间

Linux 0.12运行在x86保护模式下,支持4GB线性地址空间和分页机制。系统将16MB物理内存划分为几个区域:低1MB内存用于内核代码、数据和缓冲区(包括0-640KB的内核程序和640KB-1MB的显存和BIOS区域),1MB以上的主内存区用于用户进程的页面分配。

每个进程都有自己的4GB线性地址空间。0-64MB的区域用于任务号0-63的64个进程,每个进程占据64MB虚拟空间(即使实际可用物理内存远小于这个值)。进程的地址空间通过页目录和页表映射到物理内存。进程0使用0-64MB线性地址,进程1使用64-128MB线性地址,以此类推。这种线性地址的分配方式简单直接,但限制了最大进程数为64个。

地址转换采用二级页表机制。页目录表位于物理地址0处,包含1024个页目录项,每项4字节。页目录项中的高20位指向一个页表的物理地址,低12位是标志位(P存在位、R/W读写位、U/S用户/内核位等)。每个页表包含1024个页表项,每项4字节,结构与页目录项类似。通过将32位线性地址的高10位作为页目录索引,中间10位作为页表索引,低12位作为页内偏移,即可完成线性地址到物理地址的转换。

线性地址到物理地址

举个例子,线性地址 0x12345678 的地址转换过程如下:其高 10 位(0x048)作为页目录索引,与 CR3 寄存器中的页目录表基址结合定位到具体的页目录项,从中取出页表的物理地址;中间 10 位(0x135)作为页表索引,与页表物理地址结合定位到页表项,从中取出物理页面的起始地址;最后加上低 12 位偏移量(0x678),即可得到最终的物理地址。

在实际的内存布局中,内核的前160个页面(640KB)被映射到物理内存的低端,这部分内存由内核和所有进程共享,不执行写时复制。每个用户进程的代码段和数据段从其64MB空间的起始处开始,通过分页机制映射到主内存区中的物理页面。进程的页表保存在主内存区动态分配的页面中,fork时为子进程新建页表并复制父进程的页表项(设置为只读以实现写时复制)。

物理与线性地址的宏定义

在mm/memory.c中,内核通过一组宏来描述主内存区的范围以及线性地址 → mem_map索引的转换关系:

1
2
3
4
5
6
7
8
9
10
11
12
13

// mm/memory.c - 内存布局相关宏#define LOW_MEM  0x100000           /* 低端1MB以内留给内核和硬件 */#define PAGING_MEMORY (15*1024*1024)/* 可分页内存大小=15MB */#define PAGING_PAGES  (PAGING_MEMORY >> 12) /* 可管理的物理页面数=15MB/4KB=3840 *//* * 将物理地址addr转换为mem_map[]数组的索引 * 只对1MB以上的主内存区有效 */#define MAP_NR(addr)  (((addr) - LOW_MEM) >> 12)#define USED 100                    /* mem_map中USED=100表示“已占用” */

  • • LOW_MEM: 表示主内存区的起始物理地址(1MB),其下方由内核和硬件占用。
  • • PAGING_MEMORY / PAGING_PAGES: 描述了最多支持的分页内存大小以及对应页面数。
  • • MAP_NR(addr): 用于将一个物理地址映射到mem_map[]中的下标,方便记录该物理页面的引用计数。

页目录与页表的初始化:paging_init()

内核在启动完成基本初始化后,会调用paging_init()来建立内核和所有任务共享的页目录和页表。下面是经简化并加上详细注释的核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

// mm/memory.c - 建立内核页表unsigned long pg_dir[1024];     /* 页目录表,占4KB,对齐在0地址附近 */void paging_init(unsigned long start_mem, unsigned long end_mem){    /*     * start_mem: 可用内存起始地址(通常是1MB)     * end_mem  : 可用内存结束地址(不超过16MB)     * 本函数的任务:     *   1. 建立从 0 到 end_mem 的线性地址到物理地址的页表映射     *   2. 将页目录基址写入cr3     *   3. 打开cr0中的分页使能位PG     */    unsigned long * pg_table;    unsigned long tmp;    int i, j;    /*     * 首先清零整个页目录,避免残留无效项     */    for (i = 0; i < 1024; i++)        pg_dir[i] = 0;              /* P=0 表示该页目录项无效 */    /*     * 从start_mem开始,每4KB分配一个页表,用于映射线性地址空间     * Linux 0.12中,内核建立了恒等映射:线性地址 = 物理地址     */    tmp = 0;                        /* tmp用于记录当前映射的物理地址 */    for (i = 0; tmp < end_mem; i++) {        /* 为每个页目录项分配一个页表页面 */        pg_table = (unsigned long *) start_mem;  /* 页表本身放在主内存区 */        start_mem += PAGE_SIZE;     /* 下一个页表的存放位置 */        /*         * 设置页目录项:         *   - 高20位指向页表的物理地址         *   - 低12位标志: P=1,R/W=1,U/S=0         */        pg_dir[i] = (unsigned long)pg_table | 7; /* 0b111 = P+R/W+U/S内核 */        /* 填充当前页表: 建立4KB*1024=4MB的线性→物理恒等映射 */        for (j = 0; j < 1024 && tmp < end_mem; j++) {            *pg_table = tmp | 7;   /* 物理地址tmp,同样P=1,R/W=1,U/S=0 */            pg_table++;            tmp += PAGE_SIZE;      /* 映射下一个4KB页面 */        }    }    /*     * 将页目录基址写入cr3,告诉CPU页目录表的位置     */    asm volatile ("movl %0,%%cr3"::"r"(pg_dir));    /*     * 打开cr0的PG位 (bit 31),正式启用分页机制     */    asm volatile (        "movl %%cr0, %%eax\n\t"   /* eax = cr0 */        "orl  $0x80000000, %%eax\n\t" /* 置PG位 */        "movl %%eax, %%cr0\n\t"   /* 写回cr0 */        : : : "eax");}

注意: 上述代码略去了与缓冲区、内核镜像重定位等细节相关的部分,目的是突出“如何从0地址开始建立线性地址到物理地址的恒等映射”。

每个进程的64MB线性地址空间如何实现

Linux 0.12中,每个任务(task)拥有一个独立的LDT,其中代码段和数据段的基址不同,从而实现“每个进程有自己的64MB线性空间”的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

// include/linux/sched.h 中的LDT布局/* * 每个进程的LDT中有3个描述符: *   0: 空描述符 *   1: 代码段描述符 (base = 进程线性空间起始) *   2: 数据段描述符 (base = 进程线性空间起始) */struct desc_struct ldt[3];// 设置进程p的代码/数据段基址,使其获得自己的64MB线性空间void set_base(struct desc_struct * desc, unsigned long base);void copy_mem(int nr, struct task_struct * p){    /*     * 省略部分代码...     * 针对任务号nr,将LDT中的代码段和数据段基址分别设置为:     *   base = nr * 64MB     */    unsigned long code_limit = 0x4000000;   /* 64MB = 0x4000000 */    unsigned long base = nr * code_limit;   /* 每个任务的线性空间起点 */    set_base(p->ldt + 1, base);  /* 代码段描述符 */    set_base(p->ldt + 2, base);  /* 数据段描述符 */    /*     * 这样, 当进程使用逻辑地址0时, 实际线性地址是 base+0     *   - 任务0: base=0,   线性0..64MB     *   - 任务1: base=64MB,线性64..128MB     *   - ...     */}

结合前面的页表恒等映射,可以这样理解:

  • • 物理内存0 ~ end_mem被映射到线性地址0 ~ end_mem;
  • • 每个进程通过不同的段基址将“自己的0地址”平移到不同的64MB窗口;
  • • 通过分页机制,用户空间的访问最终仍然落到同一份页表和物理内存上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

任务号 (Task ID)(例如: 0, 1, 2, 3 ...)      │      ▼┌───────────────────────────────────────────┐│                    64MB 线性窗口                                                     ││                                                                                                ││   每个任务拥有独立的 64MB 线性地址空间                                   ││   窗口基址 = 任务号 × 64MB                                                      ││                                                                                                ││   示例:                                                                                      ││     任务0: 线性窗口 0x00000000 - 0x03FFFFFF (0-64MB)             ││     任务1: 线性窗口 0x04000000 - 0x07FFFFFF (64-128MB)         ││     任务2: 线性窗口 0x08000000 - 0x0BFFFFFF (128-192MB)       ││     任务3: 线性窗口 0x0C000000 - 0x0FFFFFFF (192-256MB)       │└───────────────────────────────────────────┘      │      ▼┌───────────────────────────────────────────┐│                    页表/分段映射                                                        ││                                                                                                ││   线性地址 → 分页机制 → 物理地址                                             ││   (或通过段基址直接映射)                                                           │└───────────────────────────────────────────┘      │      ▼┌───────────────────────────────────────────┐│                    物理地址                                                                ││                                                                                                ││   最终访问的实际内存地址                                                           │└───────────────────────────────────────────┘

5.2 物理内存管理

物理内存管理的核心数据结构是mem_map数组,定义在mm/memory.c中。这是一个unsigned char数组,每个元素对应一个4KB物理页面,元素的值表示该页面的引用计数(被多少个进程或内核结构引用)。mem_map最多可以管理15MB的主内存区(PAGING_PAGES=3840个页面)。

mem_map数组与mem_init()初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

// mm/memory.c - 物理内存管理核心数据结构unsigned char mem_map[PAGING_PAGES] = {0,};/* * mem_map[i]描述了物理页面(LOW_MEM + i*4096)的使用情况: *   =0   : 空闲页面,可供分配 *   =1   : 被1个进程/内核结构使用 *   =n   : 被n个进程共享(典型场景是写时复制COW) *   =USED(100): 表示“不可分配”,用于保留内核所占用的页面 */void mem_init(long start_mem, long end_mem){    int i;    HIGH_MEMORY = end_mem;         /* 记录系统可用物理内存的上限 */    /*     * 1. 初始状态下,将所有可分页内存标记为USED,避免误分配     *    这样做的好处是:接下来我们只需要把真正“空闲”的区间清零即可。     */    for (i = 0; i < PAGING_PAGES; i++)        mem_map[i] = USED;         /* 100 表示“已占用/保留” */    /*     * 2. 根据start_mem和end_mem,将主内存区对应的mem_map元素清零,表示可分配     *    - LOW_MEM以下(1MB)是内核和硬件保留区,不参与分配     *    - (LOW_MEM, start_mem)之间通常用于内核镜像、缓冲区等,也不算进主内存区     */    i = MAP_NR(start_mem);         /* 计算start_mem对应的页面号 */    int end = MAP_NR(end_mem);     /* 计算end_mem对应的页面号 */    while (i < end)        mem_map[i++] = 0;          /* 置0表示空闲页面 */}

  • • mem_map中值为 USED 的页面永远不会被get_free_page()分配,通常对应内核占用的页面;
  • • 值为 0 表示空闲;值大于0表示此页面被若干个进程共享。
1
2
3
4
5
6
7
8
9
10

mem_map数组   │   ├── 索引0                       → 内核页面 = USED   ├── 索引1~255               → 内核与缓冲 = USED   └── 索引256~3839         → 主内存区            │            ├── 值=0  → 空闲页面            ├── 值=1  → 被1个进程占用            ├── 值=2  → 被2个进程共享            └── 值=3  → 被3个进程共享

get_free_page(): 分配一个物理页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

// mm/memory.c - 从mem_map中分配一个空闲页面unsigned long get_free_page(void){    int i;    /*     * 从高地址向低地址扫描mem_map,优先使用高端内存,     * 可以在一定程度上减少与内核低端内存的冲突。     */    for (i = PAGING_PAGES - 1; i >= 0; i--) {        if (mem_map[i] == 0) {         /* 找到一个空闲页面 */            mem_map[i] = 1;            /* 引用计数=1,表示被占用 */            /* 计算该页面的物理地址: LOW_MEM + i*PAGE_SIZE */            unsigned long addr = LOW_MEM + (i << 12);            /* 将新页面内容清零,避免泄漏旧数据 */            memset((void *)addr, 0, PAGE_SIZE);            return addr;               /* 返回物理地址 */        }    }    return 0;  /* 没有空闲页面,后续代码会尝试swap换出或直接报错 */}

注意: 在完整源代码中,当get_free_page()返回0时,上层有时会调用oom()或尝试swap_out,视具体调用场景而定。这里为了突出核心逻辑,省略了换页部分的细节。

1
2
3
4
5

get_free_page 流程:   │   扫描 mem_map 找 0   │   找到后设为 1 并返回物理地址

free_page(): 释放一个物理页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

// mm/memory.c - 释放一个物理页面void free_page(unsigned long addr){    /*     * 只允许释放1MB以上的主内存区页面。     * 低端内存(内核/硬件)是保留区域,不能被free_page释放。     */    if (addr < LOW_MEM)        return;                      /* 直接返回,忽略释放请求 */    if (addr >= HIGH_MEMORY)        /* 超出物理内存上限 */        panic("trying to free nonexistent page");    int nr = MAP_NR(addr);          /* 物理地址 -> mem_map索引 */    if (mem_map[nr] == 0)           /* 引用计数本就为0,说明逻辑错误 */        panic("trying to free free page");    mem_map[nr]--;                  /* 引用计数减1 */}

  • • 引用计数减到0之前:表示仍有其他进程在使用该页面,不能回收;
  • • 减到0之后:下一次调用get_free_page()时,这个页面就会被重新分配。

结合get_free_page()free_page(),我们就有了一套最基本的物理内存分配/释放接口,其他内存管理函数(如页面异常处理、写时复制、页面交换)都建立在这套接口之上。

1
2
3
4
5
6
7
8
9

free_page 流程:   │   mem_map 对应项减 1   │   ┌─── 减到0? ───┐   │                          │  是                          否   │                          │  页面变为空闲      仍被其他进程引用

5.3 页面异常处理

页面异常(Page Fault)是虚拟内存机制的核心。当CPU访问一个线性地址时,如果对应的页表项不存在(P位=0)或者违反了保护规则(例如写只读页面),CPU会触发INT 14页面异常,跳转到page_fault异常处理程序(定义在mm/page.s中)。

page_fault首先保存寄存器现场,然后从CR2寄存器读取引发异常的线性地址,从栈中取出错误码。错误码的第0位表示是缺页异常(0)还是页保护异常(1),第1位表示是读访问(0)还是写访问(1),第2位表示是内核态(0)还是用户态(1)。根据第0位,page_fault调用do_no_page()处理缺页,或者调用do_wp_page()处理写保护异常。

do_no_page()处理缺页异常,它的任务是为访问的线性地址分配物理页面并建立映射。如果该地址位于进程的可执行文件映射区域,do_no_page()会从可执行文件中读取对应内容到新分配的页面(这就是需求加载,demand loading);如果是数据段或栈的访问,则分配一个零页面。建立页表项后,该异常被修复,进程可以继续执行,就像什么都没发生过。

do_wp_page()处理写保护异常,它是实现写时复制(Copy-On-Write,COW)的关键。当进程试图写一个只读页面时,如果该页面的引用计数为1(只有当前进程使用),do_wp_page()将页表项改为可写,进程可以直接写入;如果引用计数大于1(多个进程共享,例如fork后的父子进程),do_wp_page()会分配一个新的物理页面,将原页面内容复制到新页面,然后将当前进程的页表项指向新页面并设为可写,同时将原页面的引用计数减1。这样就实现了写时复制:多个进程共享只读页面,只有在写入时才真正复制页面。

do_wp_pagedo_no_pagepage_faultCPU进程do_wp_pagedo_no_pagepage_faultCPU进程alt[引用计数=1][引用计数>1]alt[缺页异常(P=0)][写保护异常(P=1,写只读页)]访问线性地址查页表,发现页不存在或写保护触发INT 14保存现场,读CR2和错误码调用do_no_page分配物理页面建立页表映射返回调用do_wp_page检查引用计数改为可写分配新页面并复制修改页表指向新页面返回恢复现场iret返回继续执行,访问成功

5.4 写时复制机制

写时复制是Linux内存管理的一项重要优化技术,它让fork()系统调用几乎无需复制内存就能创建子进程。copy_page_tables()函数实现了这个机制,它在fork时被copy_mem()调用,负责为子进程复制页表。

copy_page_tables()并不复制物理页面的内容,而是让子进程的页表项指向和父进程相同的物理页面,同时将这些页表项的R/W位清零,设为只读。这样父子进程共享相同的物理页面,但都不能写入。当父进程或子进程任一方试图写入共享页面时,CPU会触发页保护异常,do_wp_page()检测到引用计数大于1,就分配新页面并复制内容,然后修改触发异常进程的页表项指向新页面并设为可写。

这种机制的优势是明显的。fork后如果子进程立即调用exec加载新程序,那么从父进程继承的页面根本不会被写入,直接被释放,如果事先复制了所有页面就完全是浪费。即使父子进程都会修改内存,写时复制也能将复制操作延迟到真正需要时才执行,并且只复制被修改的页面。这就像图书馆的复印政策:不要求每个读者都复印整本文,只有当读者需要在书上做笔记时才复印那一页。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

copy_page_tables 复制页表   │   ├── 子进程页表项指向父进程的物理页面   │   ├── 父子进程页表项都设为只读 (R/W=0)   │   └── 物理页面引用计数 +1                      │                      ▼        父子进程正常读取页面                      │                      ▼   ┌─── 进程写入页面? ────────┐   │                                                │  否                                                是   │                                                │   │                                                ▼   │                                      触发页保护异常   │                                                │   │                                                ▼   │                           do_wp_page 检查引用计数 >1   │                                                │   │                                                ▼   │                                     分配新物理页面   │                                                │   │                                                ▼   │                               复制原页面内容到新页面   │                                                │   │                                                ▼   │                               修改写进程页表指向新页面   │                                                │   │                                                ▼   │                            设置新页表项为可写 (R/W=1)   │                                                │   │                                                ▼   │                                     原页面引用计数 -1   │                                                │   │                                                ▼   │                                进程继续执行,写入成功   │                            └────── 回到正常读取 ◀─────┘

5.5 页面交换机制

Linux 0.12引入了基本的页面交换(Swap)功能,允许将不常用的内存页面交换到磁盘上的交换设备,从而支持超过物理内存大小的虚拟内存。swap.c文件实现了交换页面管理,swap_bitmap数组记录交换设备中哪些页槽被占用。

当物理内存不足时,get_free_page()会调用try_to_swap_out()尝试换出页面。try_to_swap_out()扫描所有进程的页表,寻找合适的页面换出候选者(通常选择最近最少使用的页面)。找到后,它将该页面内容写入交换设备的一个空闲页槽,然后修改页表项:将P位清零表示页面不在内存,将页槽号保存在页表项的高位,释放物理页面。

当进程访问已被换出的页面时,会触发缺页异常。do_no_page()检测到页表项P位为0但高位不为0(保存了页槽号),就知道这是一个已换出的页面。它分配新的物理页面,从交换设备的对应页槽读取内容,建立页表映射,释放交换设备页槽。这样页面就从磁盘换回到内存,进程可以继续访问。

页面交换让系统能够运行内存需求超过物理内存的程序,但代价是性能下降。磁盘访问比内存访问慢几个数量级,频繁的换入换出会导致系统卡顿(这称为thrashing,颠簸)。因此页面交换是一种以时间换空间的权衡策略。

1
2
3
4
5
6

物理内存 (mem_map)                   交换设备 (swap_bitmap)┌─────────────┐                 ┌────────────────┐│ 空闲页面(0)           │ ◄────► │ bit=1 → 页槽空闲         │├─────────────┤                 │ bit=0 → 页槽已占用      ││ 已占用页面(>0)      │                 └────────────────┘└─────────────┘

5.6 共享页面与内核空间

Linux 0.12实现了简单的共享页面机制。内核代码和数据占据物理内存的低640KB,这部分内存被映射到所有进程的线性地址空间低端(通过所有进程共享的内核页表实现)。由于这部分页表项的R/W位为0(只读),用户进程无法修改内核内存,保证了系统安全性。

此外,多个进程执行同一个可执行文件时(例如多个用户同时运行/bin/sh),它们的代码段可以共享物理页面。当do_no_page()从可执行文件加载页面时,它会检查该页面是否已被其他进程加载,如果是就增加引用计数并共享,而不是重新加载。这样可以节省内存,提高系统性能。

内核自身也使用虚拟内存,但内核的页表是固定的,在head.s中初始化时就建立好了。内核使用的物理页面(如task_struct、缓冲区等)通过get_free_page()分配,但不会被换出到交换设备,因为内核代码不能被缺页异常中断(会导致递归异常)。

内存区域
物理地址范围
用途
特点
低640KB
0-0xA0000
内核代码与数据
所有进程共享,只读
640KB-1MB
0xA0000-0x100000
显存与BIOS
硬件占用
1MB以上主内存区
0x100000-end
用户进程页面,页表,缓冲区
动态分配,支持换页

5.7 实际示例:一个完整的fork-exec过程中的内存变化

让我们通过一个实际场景理解内存管理的完整流程。进程A(PID=5)执行fork()创建子进程B(PID=6)。copy_process()为进程B分配task_struct页面,然后调用copy_mem()复制内存空间。

copy_mem()首先为进程B分配页表页面(每个页目录项对应的页表需要一个页面),然后调用copy_page_tables(0, 64MB*5, 进程A的内存大小)。假设进程A使用了10个页面,copy_page_tables()为进程B建立页表项,让这10个页表项都指向进程A的物理页面,并将进程A和进程B的页表项R/W位都设为0(只读)。对应的10个物理页面的mem_map引用计数从1增加到2。此时进程A和进程B共享这10个页面。

fork返回后,进程B执行execve("/bin/ls")加载新程序。do_execve()首先调用free_page_tables()释放进程B从进程A继承的页表和页面。free_page_tables()将10个共享页面的引用计数减1(从2变为1),页面回归进程A独占但不释放物理页面。然后do_execve()打开/bin/ls可执行文件,为进程B分配新的页表,但不分配物理页面(采用需求加载)。

进程B开始执行/bin/ls的第一条指令时,由于页面不存在,触发缺页异常。do_no_page()被调用,它调用get_free_page()分配一个空闲页面(假设是第100号页面),然后从/bin/ls文件中读取对应的代码段内容到该页面,建立页表映射。进程B继续执行,每次访问新的代码或数据页面都会触发缺页异常,逐步将/bin/ls加载到内存。

进程B在执行过程中,假设修改了栈上的一个变量,该变量所在的页面是进程B独占的,可以直接写入。如果进程A也修改了之前共享的页面(现在已不再共享,因为进程B执行了exec),由于引用计数已经是1,do_wp_page()直接将页表项改为可写,无需复制页面。

通过本章的学习,我们深入理解了Linux 0.12的内存管理系统:从物理内存管理到虚拟内存映射,从页面分配回收到页面异常处理,从写时复制机制到页面交换,以及共享页面的实现。这套系统虽然相对简单,但已经包含了现代操作系统内存管理的核心思想,为进程隔离、资源共享和虚拟内存提供了坚实的基础。

5.8 参考资料

本章内容基于以下资料编写:

Intel官方文档

  • • Intel 80386 Programmer's Reference Manual (1986)
    • • Chapter 5: Memory Management - 详细描述了分段和分页机制
    • • Chapter 9.6: Page-Fault Exception - 介绍了页面异常的错误码和处理
    • • 在线阅读:https://css.csail.mit.edu/6.858/2014/readings/i386.pdf

Linux 0.12源代码文件

  • • mm/memory.c - mem_init、get_free_page、free_page、copy_page_tables、do_no_page、do_wp_page
  • • mm/page.s - page_fault页面异常汇编入口
  • • mm/swap.c - try_to_swap_out、swap_in页面交换功能
  • • include/linux/mm.h - 内存管理相关宏定义和常量

"不积跬步,无以至千里;不积小流,无以成江海。" —— 荀子

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 20:46:16 HTTP/2.0 GET : https://f.mffb.com.cn/a/493112.html
  2. 运行时间 : 1.532746s [ 吞吐率:0.65req/s ] 内存消耗:4,633.10kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=27681609187cdc02d86a423f4797c79d
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001028s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001422s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.101300s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.101357s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001814s ]
  6. SELECT * FROM `set` [ RunTime:0.101172s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001636s ]
  8. SELECT * FROM `article` WHERE `id` = 493112 LIMIT 1 [ RunTime:0.101479s ]
  9. UPDATE `article` SET `lasttime` = 1783082777 WHERE `id` = 493112 [ RunTime:0.656763s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000833s ]
  11. SELECT * FROM `article` WHERE `id` < 493112 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.050948s ]
  12. SELECT * FROM `article` WHERE `id` > 493112 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.077523s ]
  13. SELECT * FROM `article` WHERE `id` < 493112 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.044081s ]
  14. SELECT * FROM `article` WHERE `id` < 493112 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.025255s ]
  15. SELECT * FROM `article` WHERE `id` < 493112 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.045713s ]
1.537333s