C++原生指针(如int、void)不参与内存分页管理,仅存储虚拟地址;页表设置、分配、TLB刷新及缺页处理均由操作系统与MMU完成,访问成败取决于该地址是否已被mmap/VirtualAlloc等系统调用映射。

指针本身不管理内存分页,操作系统和MMU才管
直接说结论:int*、void* 或任何 C++ 原生指针,都不参与页表设置、页分配、TLB 刷新或缺页异常处理。它们只是存储一个虚拟地址的数值,访问时由 CPU 的 MMU 自动完成页号→物理帧的翻译。你写的 ptr[1024] 能否访问成功,取决于该地址是否已被 OS 映射(比如通过 mmap 或 VirtualAlloc),而不是指针类型或操作符重载。
需要手动干预分页时,必须调用系统 API
如果你真要控制页面粒度(如按 4KB 对齐、设置只读/不可执行、锁定到物理内存),C++ 标准库完全不提供接口。必须用平台特定系统调用:
- Linux/macOS:用
mmap替代new,传入MAP_ANONYMOUS | MAP_PRIVATE,并指定PROT_READ | PROT_WRITE等保护标志 - Windows:用
VirtualAlloc,注意lpAddress建议设为nullptr,flAllocationType用MEM_COMMIT | MEM_RESERVE - 所有平台:对齐必须显式做——
mmap要求addr和length都是页大小(如 4096)的倍数;VirtualAlloc的dwSize同样需向上取整到页边界
示例(Linux):
void* page = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (page == MAP_FAILED) { /* 处理错误 */ }
// 使用后必须 munmap(page, 4096)
RAII 封装页内存时,别误用智能指针
std::unique_ptr<char[]> 或 std::shared_ptr<int> 无法安全接管 mmap 分配的内存——因为它们默认调用 delete[] 或 delete,而页内存必须用 munmap / VirtualFree 释放。否则会触发 SIGSEGV 或资源泄漏。
- 正确做法:自定义 deleter,例如
std::unique_ptr<char[], void(*)(void*, size_t)>包裹munmap - 更稳妥:写一个轻量 wrapper 类,构造时
mmap,析构时munmap,且禁止拷贝(只允许移动) - 切忌把页地址赋给裸指针后长期持有——页可能被
mprotect改权限,或被mremap迁移,裸指针不会自动失效,但访问会 crash
分页相关 bug 往往表现为“合法地址却段错误”
常见现象不是编译报错,而是运行时随机崩溃或 Segmentation fault (core dumped),尤其在以下场景:
立即学习“C++免费学习笔记(深入)”;
- 用
malloc分配 1KB,却当成页对齐内存去调mprotect(地址未对齐,系统拒绝) -
mmap成功返回非空地址,但忘记检查PROT_EXEC是否被内核禁用(如开启 SMEP/SMAP 或 SELinux 策略) - 多线程中一个线程
mprotect修改某页为只读,另一线程仍尝试写——不抛异常,直接终止进程 - 在 ASLR 开启环境下硬编码页地址(比如调试时记下的
0x7f8a...1000),下次运行地址变了,再用就非法
查这类问题优先用 /proc/[pid]/maps(Linux)或 vmmap(macOS)确认目标地址是否真在映射范围内、权限是否匹配。
真正难的从来不是写对指针算术,而是理解虚拟内存生命周期里谁负责映射、谁负责保护、谁负责释放——这些角色 C++ 指针一个都不扮演。


















