# 缓存清理(drop\_caches)和内存压缩(compact\_memory)

在长时间运行的Linux操作系统中，系统日志有时会出现无法分配高阶内存的报错信息：

```
Aug  4 22:58:15 server1 kernel: : [69229257.683658] xenwatch: page allocation failure. order:4, mode:0xd0
Aug  4 22:58:15 server1 kernel: : [69229257.683665] Pid: 168, comm: xenwatch Tainted: GF          ---------------    2.6.32-358.23.2.el5.x86_64 #1
Aug  4 22:58:15 server1 kernel: : [69229257.683672] Call Trace:
Aug  4 22:58:15 server1 kernel: : [69229257.683688]  [<ffffffff8112723a>] ? __alloc_pages_nodemask+0x67a/0x8c0
Aug  4 22:58:15 server1 kernel: : [69229257.683697]  [<ffffffff8126082f>] ? number+0x2ff/0x330
Aug  4 22:58:15 server1 kernel: : [69229257.683706]  [<ffffffff81162260>] ? kmem_getpages+0x60/0x150
```

此时使用`cat /proc/buddyinfo`观察内存order分配情况，可以看到内存碎片化严重（大量的低阶内存页，但是几乎没有高阶内存页）

```
#cat /proc/buddyinfo
Node 0, zone      DMA      2      2      2      1      2      1      1      0      0      0      2
Node 0, zone    DMA32  32995   4377    762    211    157    108     68     23      3      0      0
Node 0, zone   Normal 127146  68215   1614      0      0      0      0      0      0      0      1
```

处理的方法主要采用`drop_caches`（抛弃缓存），然后使用`compact_memory`合并低阶内存页来创造出足够的高阶内存页。

## `drop_caches`

Linux Kernel 2.6.16之后的内核提供了一个设置内核抛弃 页缓存 `和/或` 目录(dentry)和索引节点（inode）缓存，这样可以释放出大量内存。

* 释放页缓存

```
echo 1 > /proc/sys/vm/drop_caches
```

* 释放目录和索引节点缓存（inode and dentry cache）

```
echo 2 > /proc/sys/vm/drop_caches
```

* 同时释放 页、目录、索引节点缓存：

```
echo 3 > /proc/sys/vm/drop_caches
```

上述操作是无害的操作，并且智慧释放完全没有使用的内存对象。脏对象（dirty objects）将继续被使用直到它们被写入到磁盘中，所以内存脏对象不会被释放。不过，如果在执行`drop_caches`之前执行`sync`指令，则会将脏对象刷新到磁盘中，这样`drop_caches`操作会释放出更多内存。

注意：`drop_caches`需要花费一些时间（在终端中可以看到大约几十秒时间），此时再次使用`cat /proc/buddyinfo`可以看到立即出现了大量高阶内存页。

但是`drop_caches`这个触发动作是一次性的，也就是说，并不因为`cat /proc/sys/vm/drop_caches`时显示输出内容是`3`就表示系统不缓存内容。相反，一旦完成`drop_caches`，系统立即自动对后续内存对象进行缓存。所以要再次触发缓存清理，需要再次执行 `echo 3 > /proc/sys/vm/drop_caches`。

> 如果重复`echo 3 > /proc/sys/vm/drop_caches`不能再次释放缓存，可以先尝试`echo 0 > /proc/sys/vm/drop_caches`然后再执行`echo 3 > /proc/sys/vm/drop_caches`。

## `compact_memory`

当内核编译参数设置了`CONFIG_COMPACTION`，就会在`/proc/sys/vm/compact_memory`有入口文件。将`1`写入到这个文件，则所有的zones就会进行压缩，以便能够尽可能地提供连续内存块。对于需要分配大页的时候这个功能非常重要，不过，进程会在需要时直接进行内存压缩（compact memory）。

## 实际操作案例

* 检查系统缺乏高阶内存

```
#cat /proc/buddyinfo
Node 0, zone      DMA      2      2      2      1      2      1      1      0      0      0      2
Node 0, zone    DMA32  32995   4377    762    211    157    108     68     23      3      0      0
Node 0, zone   Normal 127146  68215   1614      0      0      0      0      0      0      0      1
```

* 执行缓存释放

```
#echo 3 > /proc/sys/vm/drop_caches
```

* 完成后检查内存页

```
#cat /proc/buddyinfo
Node 0, zone      DMA      2      2      2      1      2      1      1      0      0      0      2
Node 0, zone    DMA32  76826  65298  43784  20780   5272    616     90     32      4      0      0
Node 0, zone   Normal 524538 365499 176074  45644   4338    140      6      0      0      0      1
```

* 然后执行内存压缩

```
#echo 1 > /proc/sys/vm/compact_memory
```

* 然后再次检查内存页分布，可以看到逐渐出现更多的高阶内存页

```
#cat /proc/buddyinfo
Node 0, zone      DMA      2      2      2      1      2      1      1      0      0      0      2
Node 0, zone    DMA32  18217  13464   8621   4666   2654   2087   1609   1040    517    130      3
Node 0, zone   Normal 145048 131183  76864  38454  20405  11854   5149   1143     96      3      1
```

## 参考

* [Drop Caches](https://linux-mm.org/Drop_Caches)
* [Documentation for /proc/sys/vm/\*    kernel version 2.6.29](https://www.kernel.org/doc/Documentation/sysctl/vm.txt)


---

# 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://huataihuang.gitbook.io/cloud-atlas-draft/os/linux/kernel/memory/drop_caches_and_compact_memory.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.
