当前位置:首页>Linux>动态扩容与缩减:Linux 内存热插拔流程与内存块迁移机制

动态扩容与缩减:Linux 内存热插拔流程与内存块迁移机制

  • 2026-06-29 17:53:04
动态扩容与缩减:Linux 内存热插拔流程与内存块迁移机制

本文基于 Linux 7.0 源码,文件路径均相对于内核根目录。 核心文件:mm/memory_hotplug.c(2432 行)、mm/migrate.cmm/page_alloc.cinclude/linux/memory_hotplug.hdrivers/base/memory.c

1. 一个具体的痛点

假设你管理一个 256 节点的 KVM 集群,每台宿主机 64GB 物理内存。某个月底:

  • 节点 #127 跑满了,但上面有 3 个不能中断的生产容器

  • 节点 #088 空闲率 80%,你希望把它的内存拔给 #127 用

如果没有内存热插拔,你只有两个选择:

  1. 关机插内存 → 生产服务中断

  2. 关机迁移 VM → 停机时间 + 数据迁移开销

有了内存热插拔echo offline > /sys/devices/system/memory/memoryX/state 触发页面迁移,内核把这块内存上的所有已分配页面搬走,然后物理拆除映射。全程不需要重启、不需要停服务。

现代场景中,这个机制更是 CXL 内存扩展、virtio-mem 动态内存调整、以及云厂商按需弹性的基础设施。

2. 本文目标

本文以 mm/memory_hotplug.c 为核心,分析三个问题:

  1. 热添加/热移除的完整执行流程:从 sysfs/驱动 API 到物理映射建立/拆除

  2. offline 阶段的页面迁移机制:如何把已分配的页面从一个物理区域搬到另一个

  3. 设计取舍:为什么必须是两阶段(offline → remove)?迁移失败怎么办?哪些页面不可迁移?

心智模型:内存热插拔回答的是同一个问题 —— 如何在不重启的情况下增减物理内存。 区别在于两个方向的操作难度不对称:

方向
核心问题
关键机制
热添加 (hot-add)
建立物理→虚拟映射
arch_add_memory()
 → sparse_add_section()
热移除 (hot-remove)
先把页面搬走,再拆除映射
offline_pages()
 → migrate_pages() → __remove_pages()

热添加是单向操作:只要地址空间合法,直接建立映射即可。 热移除是双向操作:必须先确认没有人在用这块内存,才能安全拆除。这就是两阶段设计的根本原因。

3. 前置知识

  • SPARSEMEM 内存模型:唯一支持热插拔的内存模型,以 section 为粒度(x86_64 上 128MB–512MB,取决于 CONFIG_SECTION_SIZE_BITS)。FLATMEM 不支持热插拔。

  • struct page / vmemmap:每个物理 page 对应一个 struct page,vmemmap 是虚拟地址空间中预分配的 struct page 区域。

  • ZONE_MOVABLE:可迁移页面集中在此 zone,是内存 offlining 的前提。

  • Folio:Linux 7.0 中页面迁移的基本单位已从 page 升级为 folio。

信息来源:wiki/concepts/mm-sparsemem(SPARSEMEM section 操作)、wiki/concepts/mm-page-migration(页面迁移机制,新创建)。

4. 关键数据结构

4.1 mhp_t — 热插拔标志位

/* include/linux/memory_hotplug.h:35 */typedef int __bitwise mhp_t;#define MHP_NONE              ((__force mhp_t)0)#define MHP_MERGE_RESOURCE    ((__force mhp_t)BIT(0))#define MHP_MEMMAP_ON_MEMORY  ((__force mhp_t)BIT(1))#define MHP_NID_IS_MGID       ((__force mhp_t)BIT(2))
标志
含义
MHP_MERGE_RESOURCE
将新加内存的 iomem resource 与相邻区域合并
MHP_MEMMAP_ON_MEMORY
vmemmap 页面从新加内存自身分配(而非已有内存),减少对已有内存的压力
MHP_NID_IS_MGID
nid 参数实际是 memory group ID,需要解析为实际 node

4.2 memory_block — 用户态可见的热插拔单元

从用户态 /sys/devices/system/memory/ 看到的就是 memory block。它是热插拔的最小可见单元,通常等于一个或多个 memory section 的大小。

每个 memory block 有独立的 online/offline 状态,由 drivers/base/memory.c 管理。

4.3 memory_group — 设备内存分组

memory_group 是 Linux 7.0 引入的新机制,用于支持 CXL 等设备的物理内存分组管理。同一 group 内的 memory block 共享 online 策略。

5. Kconfig 依赖分析

5.1 MEMORY_HOTPLUG

# mm/Kconfigmenuconfig MEMORY_HOTPLUG    bool "Memory hotplug"    select MEMORY_ISOLATION    depends on SPARSEMEM              ← 只有 SPARSEMEM 支持    depends on ARCH_ENABLE_MEMORY_HOTPLUG  ← 架构级门控    depends on 64BIT                  ← 仅 64 位系统    select NUMA_KEEP_MEMINFO if NUMA

三个硬性依赖

  1. SPARSEMEM:只有 SPARSEMEM 支持 section 级别的按需分配/释放

  2. ARCH_ENABLE_MEMORY_HOTPLUG:架构必须显式声明支持

  3. 64BIT:32 位系统虚拟地址空间不足,无法支持 vmemmap 方案

5.2 MEMORY_HOTREMOVE

config MEMORY_HOTREMOVE    bool "Allow for memory hot remove"    select HAVE_BOOTMEM_INFO_NODE if (X86_64 || PPC64)    depends on MEMORY_HOTPLUG && ARCH_ENABLE_MEMORY_HOTREMOVE    depends on MIGRATION              ← 需要页面迁移支持

关键依赖 MIGRATION:没有页面迁移,offline 步骤无法执行,hot-remove 也就无从谈起。

5.3 架构支持对照表

架构
HOTPLUG
HOTREMOVE
备注
x86_64
if X86_64if MEMORY_HOTPLUG
最完整支持
arm64
无条件
无条件
完整支持
loongarch
无条件
无条件
完整支持
powerpc
无条件
无条件
完整支持
s390
if SPARSEMEM
无条件
需要 SPARSEMEM
riscv
if SPARSEMEM_VMEMMAPif MEMORY_HOTPLUG
需要 vmemmap

本锁架构(不启用):alpha, arc, arm(32), csky, hexagon, m68k, microblaze, mips, nios2, openrisc, parisc, sh, sparc, um, xtensa

5.4 子选项

config MHP_MEMMAP_ON_MEMORY    def_bool y    depends on MEMORY_HOTPLUG && SPARSEMEM_VMEMMAP && ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE

当此选项开启时,热添加内存的 vmemmap 页面从新内存自身分配,而不是从已有内存分配。这对大块内存 hotplug 场景意义重大 —— 减少了对已有内存的压力。

6. 调用链

上图展示了内存热插拔的三条核心路径:热添加路径从上到下建立映射,热移除路径先检查 offline 状态再拆除映射,offline 迁移循环(左下)反复执行 scan→migrate→isolate 直到所有页面可迁移。

6.1 热添加路径

sysfs write / ACPI event / virtio-mem driver        │        ▼    add_memory(nid, start, size, mhp_flags)        │ lock_device_hotplug()        ▼    __add_memory(nid, start, size, mhp_flags)        │        ├── register_memory_resource(start, size, "System RAM")        │       → mhp_range_allowed()          // 检查物理地址合法性        │       → __request_region()           // 在 /proc/iomem 中保留        │        ▼    add_memory_resource(nid, res, mhp_flags)        │        ├── check_hotplug_memory_range()       // 对齐检查        ├── mem_hotplug_begin()                // percpu 写锁 + CPU hotplug 读锁        ├── memblock_add_node()                // 注册到 memblock 分配器        ├── __try_online_node()                // 如 node 首次出现,初始化        ├── [分支:MHP_MEMMAP_ON_MEMORY]        │       → create_altmaps_and_memory_blocks()  // vmemmap 在新内存上        │   [否则]        │       → arch_add_memory() + create_memory_block_devices()        ├── register_memory_blocks_under_node_hotplug()        ├── firmware_map_add_hotplug()        ├── mem_hotplug_done()        └── [自动上线] mhp_get_default_online_type() != MMOP_OFFLINE                → online_memory_block()

6.2 热移除路径

用户态 sysfs / driver 请求        │        ▼    offline_pages(start_pfn, nr_pages, zone, group)        │ 迁移循环(见第 8 节)        ▼    __offline_isolated_pages()           // 从 buddy 移除隔离页面    remove_pfn_range_from_zone()        │        ▼    remove_memory(start, size)        │ lock_device_hotplug()        ▼    try_remove_memory(start, size)        │        ├── walk_memory_blocks() + check_memblock_offlined_cb()  // 检查全部 offline        ├── firmware_map_remove()        ├── mem_hotplug_begin()        ├── [无 altmap] remove_memory_block_devices() + arch_remove_memory()        │   [有 altmap] remove_memory_blocks_and_altmaps()        ├── memblock_remove()            // 如 CONFIG_ARCH_KEEP_MEMBLOCK        ├── release_mem_region_adjustable()        ├── try_offline_node(nid)        // node 无内存时 offline        └── mem_hotplug_done()

6.3 组合操作:offline + remove

/* mm/memory_hotplug.c */offline_and_remove_memory()    ├── walk_memory_blocks() + try_offline_memory_block()  // 逐个 offline    ├── try_remove_memory()                                // 物理移除    └── [部分失败] try_reonline_memory_block()             // 回滚

支持故障回滚:如果 offline 中途失败,会把已 offline 的 block 重新 online。

7. 核心执行流程:热添加走一遍

以添加 1GB 内存到 node 0 为例(x86_64, section = 128MB, 共 8 个 section):

add_memory(0, 0x100000000, 0x40000000, MHP_NONE)    │    │ 步骤 1: __add_memory() 注册 iomem resource    │   register_memory_resource(0x100000000, 0x40000000, "System RAM")    │   → /proc/iomem 中出现: "100000000-13fffffff : System RAM"    │    │ 步骤 2: add_memory_resource() 核心逻辑    │   check_hotplug_memory_range()     ← 检查 1GB 对齐到 section    │   mem_hotplug_begin()              ← 获取 percpu 写锁    │   memblock_add_node(0, 0x100000000, 0x40000000)  ← 注册到 memblock    │   __try_online_node(0)             ← node 0 可能已经 online,跳过    │    │ 步骤 3: MHP_MEMMAP_ON_MEMORY 分支    │   如果设置了 MHP_MEMMAP_ON_MEMORY:    │     create_altmaps_and_memory_blocks()    │       逐 memory block:    │         构造 vmem_altmap    │         arch_add_memory(0, block_start, block_size, &params)    │           → __add_pages() 按 section 迭代:    │               for each section:    │                   sparse_add_section()  ← 创建 struct page + 页表映射    │         create_memory_block_devices()  ← 创建 sysfs 设备节点    │   否则:    │     arch_add_memory() + create_memory_block_devices()    │    │ 步骤 4: 注册到 node    │   register_memory_blocks_under_node_hotplug()    │   firmware_map_add_hotplug()    │    │ 步骤 5: 自动上线    │   如果 mhp_get_default_online_type() != MMOP_OFFLINE:    │     online_memory_block()  ← 内存立即可用于分配    │    │ 步骤 6: 释放锁    │   mem_hotplug_done()

关键决策点MHP_MEMMAP_ON_MEMORY 标志决定了 vmemmap 页面从哪里分配。如果开启,1GB 新内存的 vmemmap 页面(约 8MB)从这 1GB 自身分配,减少了 8MB 的已有内存压力。如果关闭,则从已有内存分配。

8. 核心执行流程:offline 迁移循环

offline_pages() 是热移除的核心。它不是直接拆除映射,而是先让这块内存上的所有页面"搬家"。

8.1 offline 阶段概览

/* mm/memory_hotplug.c:1898 */int offline_pages(unsigned long start_pfn, unsigned long nr_pages,                  struct zone *zone, struct memory_group *group)

执行步骤:

阶段
代码行
说明
1. 边界检查
L1925
pageblock_aligned()
 + section 对齐
2. 空洞检查
L1937
walk_system_ram_range()
 — 确保范围内无空洞
3. 单 zone 检查
L1950
确认整个范围属于同一个 zone
4. PCP/LRU 禁用
L1961
zone_pcp_disable()
 + lru_cache_disable() — 防止并发释放
5. 页面隔离
L1965
start_isolate_page_range()
 — 设置 pageblock 隔离标志(MIGRATE_ISOLATE)
6. Node 通知
L1977
如果这是 node 最后的内存,通知 NODE_REMOVING_LAST_MEMORY
7. MEM_GOING_OFFLINE
L1987
通知 memory notifier chain
8. 迁移循环
L1994
核心循环 — 反复执行直到所有页面可迁移
9. 从 buddy 移除
L2042
__offline_isolated_pages()
 — 将隔离页面从 buddy 删除
10. 清理恢复
L2050
LRU/PCP 恢复、watermark 重算、kswapd 停止等

8.2 迁移循环详解

这是 offline 的心脏,反复执行直到所有页面迁移完毕:

/* mm/memory_hotplug.c:1994-2039 — 核心迁移循环 */do {    /* 可中断 — 用户可 Ctrl+C 终止长时间 offlining */    if (signal_pending(current)) {        ret = -EINTR;        goto failed_removal;    }    /* 设置 offlining 标志,告知其他子系统正在进行 offline */    set_mem_offlining(start_pfn, end_pfn);    /* 扫描可迁移页面:LRU 页、movable_ops 页、hugetlb 页 */    pfn = start_pfn;    do {        ret = scan_movable_pages(pfn, end_pfn, &pfn);        if (ret)            break;        /* 实际页面迁移 */        do_migrate_range(pfn, end_pfn);        cond_resched();    } while (pfn < end_pfn);    /* 释放 free hugetlb folio */    dissolve_free_hugetlb_folios(start_pfn, end_pfn);    /* 清除 offlining 标志 */    unset_mem_offlining(start_pfn, end_pfn);    /* 验证:所有页面是否已成功隔离? */    ret = test_pages_isolated(start_pfn, end_pfn, false);} while (ret == -EBUSY);

设计要点:这个循环是可中断的(signal_pending 检查),允许用户在 offlining 时间过长时终止操作。

8.3 scan_movable_pages — 判断哪些页面能搬

/* mm/memory_hotplug.c:1742 */static int scan_movable_pages(unsigned long start, unsigned long end,                              unsigned long *movable_pfn){    for (pfn = start; pfn < end; pfn++) {        page = pfn_to_page(pfn);        /* PageLRU → 可迁移(匿名页或 page cache) */        if (PageLRU(page) || page_has_movable_ops(page))            goto found;        /* PageOffline + refcount > 0 → 不可迁移 */        if (PageOffline(page) && page_count(page))            return -EBUSY;        /* hugetlb + migratable → 可迁移 */        folio = page_folio(page);        if (!folio_test_hugetlb(folio))            continue;        if (folio_test_hugetlb_migratable(folio))            goto found;        /* 跳过巨大的 hugetlb 块 */        pfn |= nr_pages - 1;    }    return -ENOENT;found:    *movable_pfn = pfn;    return 0;}

判断逻辑

条件
结果
PageLRU(page)
可迁移 — 匿名页或 page cache
page_has_movable_ops(page)
可迁移 — 驱动显式标记为 movable
PageOffline(page) && page_count(page) > 0不可迁移
 — 返回 -EBUSY
hugetlb && migratable
可迁移
其他
跳过

关键设计PageOffline 页面如果还有引用计数,说明有驱动在使用,绝对不能迁移。这是 offline 失败的常见原因。

8.4 do_migrate_range — 实际执行迁移

/* mm/memory_hotplug.c:1789 */static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn){    LIST_HEAD(source);    /* 1. 遍历 pfn 范围,对每个 folio 尝试获取引用 */    for (pfn = start_pfn; pfn < end_pfn;) {        folio = page_folio(pfn_to_page(pfn));        if (!folio_try_get(folio)) { pfn++; continue; }        /* 2. 跳过 poisoned huge folio */        if (folio_test_hugetlb(folio) && folio_test_hwpoisoned(folio))            goto next;        /* 3. 隔离到迁移列表 */        if (!isolate_folio_to_list(folio, &source))            goto next;        pfn += folio_nr_pages(folio);next:        folio_put(folio);    }    /* 4. 用 MIGRATE_SYNC 模式迁移整个列表 */    if (!list_empty(&source)) {        ret = migrate_pages(&source, alloc_migration_target, NULL, 0,                            MIGRATE_SYNC, MR_MEMORY_HOTPLUG, NULL);        /* 5. 失败时回退 */        if (ret)            putback_movable_pages(&source);    }}

迁移模式:offline 阶段使用 MIGRATE_SYNC(可以阻塞),因为它是在用户态触发的操作,可以等待 I/O 完成。与 compaction 的 MIGRATE_ASYNC(不能阻塞)形成对比。

8.5 __offline_isolated_pages — 从 buddy 移除

当迁移循环完成后,所有页面要么被搬走,要么是 free 的但被隔离了。__offline_isolated_pages() 把这些隔离页面从 buddy allocator 中永久移除:

/* mm/page_alloc.c:7368 */unsigned long __offline_isolated_pages(unsigned long start_pfn,                                        unsigned long end_pfn)

它遍历隔离的 pageblock,从 zone 的 free_area 中移除页面,并更新 managed_pages 计数。此后,这块内存的 PFN 范围不再参与 buddy 分配。

9. 分支路径分析

9.1 错误路径 — add_memory_resource

/* mm/memory_hotplug.c:1490 */int add_memory_resource(int nid, struct resource *res, mhp_t mhp_flags){    /* ... 正常流程 ... */    /* 错误回滚:按依赖关系倒序释放 */    error:        if (new_node) { node_set_offline(); unregister_node(); }    error_memblock_remove:        memblock_remove(nid, start, size);    error_mem_hotplug_end:        mem_hotplug_done();        release_memory_resource(res);        return ret;}

关键设计:错误回滚按依赖关系倒序进行(后建立的先拆除),确保状态一致性。

9.2 错误路径 — try_remove_memory

/* mm/memory_hotplug.c:2234 */static int try_remove_memory(u64 start, u64 size){    /* 1. 检查所有 memory block 是否已 offline */    walk_memory_blocks(start, size, &nid, check_memblock_offlined_cb);    if (ret)        return -EBUSY;  /* 有 block 仍然 online */    /* 2. 只有在全部 offline 后才开始物理拆除 */    mem_hotplug_begin();    /* ... arch_remove_memory, memblock_remove, ... */    mem_hotplug_done();    return 0;}

关键约束try_remove_memory() 是"尽力而为"式的 —— 如果任何 block 未 offline,直接返回 -EBUSY,不会强制拆除。这保证了内核不会在仍有页面被引用的情况下物理移除内存。

9.3 不可迁移页面的处理

/* mm/memory_hotplug.c:2010-2013 */ret = scan_movable_pages(pfn, end_pfn, &pfn);if (ret)    break;  /* -EBUSY 或 -ENOENT → 退出迁移循环 */

如果 scan 返回 -EBUSY(有 PageOffline 页面且 refcount > 0),迁移循环立即终止,offline 失败。

Open Question: 当有不可迁移页面(如驱动分配的 offline 页面)时,当前实现直接返回失败。是否有优雅的回退机制或通知机制告知用户哪些 page 不可迁移?需进一步确认。

10. 并发与生命周期分析

10.1 锁层次结构

类型
保护内容
获取位置
device_hotplug_lock
mutex(全局)
串行化所有 hotplug 操作
add_memory()
 / remove_memory() 最外层
mem_hotplug_lock
percpu 读写锁
memory 状态变更(on/offline)
mem_hotplug_begin/end()
cpus_read_lock()
CPU hotplug 读锁
CPU 热插拔期间的稳定性
mem_hotplug_begin()
 内
zone->lock
spinlock
zone 级统计(nr_isolate_pageblock)
online_pages()
 / offline_pages() 内

调用栈约束

add_memory() / remove_memory()    ├── device_hotplug_lock (mutex — 最外层)    └── mem_hotplug_lock (percpu write — 中间层)        └── zone->lock (spinlock — 最内层)

offline_pages() 和 online_pages() 在 device_hotplug_lock 之下、mem_hotplug_lock 保护下被调用。这种层次结构确保了:

  1. 同一时刻只有一个 hotplug 操作在进行

  2. 状态变更期间 CPU 不会热插拔

  3. zone 级别的统计操作是原子的

10.2 lru_cache_disable — 为什么需要全局禁用 LRU

/* offline_pages() */zone_pcp_disable(zone);     /* 禁用 per-CPC page list */lru_cache_disable();        /* 全局禁用 LRU cache */

lru_cache_disable() 是全局操作 —— 它会阻塞所有 CPU 的 LRU 添加操作。这是因为 offline 需要精确控制哪些页面在隔离范围内,如果不禁用 LRU,其他 CPU 可能把页面放到隔离范围内的 LRU list 上,导致隔离失败。

11. Kconfig 子选项与相关子系统

11.1 MHP_MEMMAP_ON_MEMORY

config MHP_MEMMAP_ON_MEMORY    def_bool y    depends on MEMORY_HOTPLUG && SPARSEMEM_VMEMMAP && ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE

默认开启(def_bool y)。当热添加 1GB 内存时,约 8MB 的 vmemmap 页面从新内存自身分配。如果不从自身分配,这 8MB 就要从已有内存中挤出来,可能导致已有内存紧张。

11.2 ZONE_DEVICE

config ZONE_DEVICE    bool "Device memory (pmem, HMM, etc.) hotplug"    depends on MEMORY_HOTPLUG && MEMORY_HOTREMOVE && SPARSEMEM_VMEMMAP && ARCH_HAS_PTE_DEVMAP

为持久化内存(PMEM)和 HMM(异构内存管理)提供 zone。它通过 SPARSEMEM 的 subsection 机制支持设备内存热插拔。

11.3 依赖 MEMORY_HOTPLUG 的关键子系统

子系统
Kconfig
用途
DAX
drivers/dax/Kconfig:68
需要 add_memory() 映射 DAX 设备
virtio-mem
drivers/virtio/Kconfig:127
虚拟机动态内存调整
ACPI
drivers/acpi/Kconfig:417
ACPI 内存热插拔事件处理
XEN_BALLOON
drivers/xen/Kconfig:15
Xen balloon 内存热插拔

12. 调试与验证方法

12.1 sysfs 操作

查看 memory block 状态

# 工作目录: 任意,需 root 权限ls /sys/devices/system/memory/# 输出: memory0  memory128  memory256  ...  block_size_bytes# 查看某个 memory block 的状态cat /sys/devices/system/memory/memory128/state# 输出: online 或 offlinecat /sys/devices/system/memory/memory128/phys_device# 输出: 0(表示物理设备编号)cat /sys/devices/system/memory/memory128/removable# 输出: 1(可移除)或 0(不可移除)

手动 offline 一个 memory block

# 工作目录: 任意,需要 root 权限# 注意:这会触发页面迁移,可能需要数分钟echo offline > /sys/devices/system/memory/memory128/state

查看 memory block 大小

cat /sys/devices/system/memory/block_size_bytes# 输出: 134217728 (128MB,x86_64 默认)

12.2 ftrace 追踪 offline 流程

# 工作目录: /sys/kernel/tracing/,需要 root 权限cd /sys/kernel/tracing/# 启用 memory hotplug 相关 tracepointecho 1 > events/memory_hotplug/enable# 追踪 offline_pages 函数echo offline_pages > set_ftrace_filterecho function > current_tracer# 触发 offline(在另一个终端)echo offline > /sys/devices/system/memory/memory128/state# 查看 tracecat trace

12.3 验证在线内存总量

# 工作目录: 任意# online 前cat /proc/meminfo | grep MemTotal# MemTotal: 65536000 kB# offline 128MB 后cat /proc/meminfo | grep MemTotal# MemTotal: 65404928 kB  (减少了约 128MB)

12.4 /proc/iomem 验证

# 工作目录: 任意# hot-add 前grep "System RAM" /proc/iomem# 100000000-23fffffff : System RAM  (4GB)# hot-add 1GB 后grep "System RAM" /proc/iomem# 100000000-27fffffff : System RAM  (5GB — 增加了 1GB)

12.5 测试环境说明

项目
要求
CPU 架构
x86_64 或 arm64(支持 MEMORY_HOTPLUG)
内核配置
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=yCONFIG_SPARSEMEM_VMEMMAP=yCONFIG_MIGRATION=y
内存
至少 2GB 以上(需要有至少一个完整的 memory block 可以 offline)
权限
root(操作 sysfs memory block 需要 root)
验证方式
对比 offline 前后 /proc/meminfo 的 MemTotal 值

13. 实践场景:何时需要关心内存热插拔

场景
涉及的机制
为什么重要
CXL 内存扩展
add_memory()
 + MHP_MEMMAP_ON_MEMORY
CXL 设备动态添加内存时,需要 vmemmap 自分配以减少对已有内存的压力
virtio-mem 动态调整
add_memory()
 + online_pages() + offline_pages()
虚拟机内存按需扩缩,host 驱动通过热插拔 API 调整 guest 内存
驱动开发:不可迁移页面
PageOffline
 + refcount
驱动分配的 offline 页面如果没释放,会阻塞整个 memory block 的 offline
云厂商弹性伸缩
memory_group
 + offline/online 策略
不同 group 的 memory block 有不同 online 策略,支持精细化资源管理
内核 oops 调试
mem_hotplug_lock
 + notifier chain
hotplug 期间的 crash 可能与锁竞争或 notifier 回调有关
大页内存与 offlining
dissolve_free_hugetlb_folios()
free hugetlb 页面会被自动释放,但 in-use hugetlb 页面会阻塞 offlining

14. 总结

内存热插拔的核心机制可以归纳为三句话:

  1. 热添加是建立映射add_memory() → arch_add_memory() → sparse_add_section() 建立物理→虚拟映射,创建 sysfs 设备节点。

  2. 热移除是两阶段操作:先 offline_pages() 迁移所有页面(scan → do_migrate_range → migrate_pages),确认没有人在用后,才 remove_memory() → __remove_pages() → sparse_remove_section() 拆除映射。

  3. 迁移是离线成功的前提MIGRATION Kconfig 是 MEMORY_HOTREMOVE 的硬依赖。不可迁移的页面(如 PageOffline + refcount > 0)是 offline 失败的常见原因。

设计取舍

  • 两阶段分离:offline(逻辑下线/迁移)和 remove(物理拆除映射)分离,保证了安全性。remove_memory() 要求先 offline,offline_and_remove_memory() 是带回滚的便捷封装。

  • 可中断 offlining:迁移循环检查 signal_pending(),允许长时间操作被用户中断。

  • vmemmap 自分配MHP_MEMMAP_ON_MEMORY 在新增内存上分配 vmemmap 页面,减少对已有内存的压力,是大块内存 hotplug 的默认行为。

  • 故障回滚offline_and_remove_memory() 在部分失败时会重新 online 已 offline 的 block,保证状态一致性。

Open Question: 当有不可迁移页面时,当前实现直接返回失败。是否有优雅的回退机制或通知机制告知用户哪些 page 不可迁移?需要在有实际驱动开发的场景下进一步确认。

15. 参考资料

  • mm/memory_hotplug.c — Linux 7.0, 2432 行

  • mm/migrate.c — 页面迁移引擎

  • mm/page_alloc.c:7368 — __offline_isolated_pages()

  • mm/compaction.c — 内存整理(复用迁移引擎)

  • include/linux/memory_hotplug.h — mhp_t 标志、API 声明

  • include/linux/migrate_mode.h — migrate_mode 枚举

  • drivers/base/memory.c — memory block 设备模型

  • mm/Kconfig:536-580 — MEMORY_HOTPLUG / MEMORY_HOTREMOVE 定义

  • wiki/concepts/mm-sparsemem — SPARSEMEM section 操作

  • wiki/concepts/mm-page-migration — 页面迁移机制(新创建)

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-04 08:26:34 HTTP/2.0 GET : https://f.mffb.com.cn/a/491094.html
  2. 运行时间 : 0.210489s [ 吞吐率:4.75req/s ] 内存消耗:4,911.48kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=eda51f37d6d91ac5f83d388399483dc6
  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.000478s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000591s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.005235s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.005786s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000591s ]
  6. SELECT * FROM `set` [ RunTime:0.000964s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000588s ]
  8. SELECT * FROM `article` WHERE `id` = 491094 LIMIT 1 [ RunTime:0.001560s ]
  9. UPDATE `article` SET `lasttime` = 1783124794 WHERE `id` = 491094 [ RunTime:0.003665s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000254s ]
  11. SELECT * FROM `article` WHERE `id` < 491094 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000420s ]
  12. SELECT * FROM `article` WHERE `id` > 491094 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.005731s ]
  13. SELECT * FROM `article` WHERE `id` < 491094 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.081039s ]
  14. SELECT * FROM `article` WHERE `id` < 491094 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.026711s ]
  15. SELECT * FROM `article` WHERE `id` < 491094 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000976s ]
0.211933s