Rust实战内存缺页检测
更多虚拟内存的详情点击https://blog.csdn.net/zhizhengguan/article/details/117568026 查看, 本次实验仅仅作为入门demo
在使用mmap申请一段匿名内存, 或者malloc函数申请的内存, 在没有访问该内存的情况下, 这段内存并不会映射到物理地址中,
so, 我们可以通过
mincore
函数不断地检测这段内存是否存在物理内存中, 来确定这段内存是否被其他的进程读取
mincore
报告在一个虚拟地址范围中哪些分页当前驻留在RAM中,因此在访问这些分页时也不会导致分页故障
mincore
返回起始地址为addr长度为length字节的虚拟地址访问中分页的内存驻留信息。addr 中的地址必须是分页对齐的,并且由于返回的信息是有关整个分页的,因此length 实际上会被向上舍入到系统分页大小的下一个整数倍。内存驻留相关的信息会通过 vec 返回,它是一个数组,其大小为(length + PAGE_SIZE – 1) / PAGE_SIZE 字节。每个字节的最低有效位在相应分页驻留在内存中时会被设置,而其他位的设置在一些 UNIX 实现上是未定义的,因此可移植的应用程序应该只测试最低有效位。
use std::ffi::c_void;
use std::fs::OpenOptions;
use std::num::NonZeroUsize;
use std::os::fd::AsRawFd;
use nix::sys::mman::{MapFlags, mmap, ProtFlags};
use std::thread;
use std::sync::{Mutex, Arc};
fn main() {
// 一个文件
let mem_size = 4096;
let f = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open("./test.mmap")
.unwrap();
f.set_len(mem_size).unwrap();
// 映射共享内存
let p1;
unsafe {
let c = mmap(None, NonZeroUsize::new(mem_size as usize).unwrap(), ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_PRIVATE, f.as_raw_fd(), 0);
match c {
Ok(p) => {
p1 = p;
}
Err(e) => {
panic!("{:?}", e.desc())
}
};
}
println!("已经映射地址为: {:?}", p1); // 这个内存映射文件的内容我之前修改的内容为 4i32
// 转换为安全类型
let safe_p1 = Arc::new(Mutex::new(unsafe { (p1 as *mut _ as *mut i32).as_ref().unwrap() }));
let safe_p2 = safe_p1.clone();
thread::spawn(move || {
// 5秒后读取共享内存的数据
thread::sleep(std::time::Duration::from_secs(5));
let p1_ref = *safe_p1.lock().unwrap();
println!("线程1: 内存的内容读取到为: {:?}", *p1_ref);
});
thread::spawn(move || unsafe {
loop {
// 每秒检测是否被映射到物理内存
thread::sleep(std::time::Duration::from_secs(1));
let p2_ref = *safe_p2.lock().unwrap();
let p2_ptr = p2_ref as *const i32 as *const c_void;
let mut buffer = [0; 128];
if libc::mincore(p2_ptr, mem_size as usize, buffer.as_mut_ptr()) == -1 {
println!("错误: {:?}", nix::errno::errno());
} else {
let c_str = unsafe {std::ffi::CStr::from_ptr(buffer.as_mut_ptr())};
println!("线程2: 内存当前状态 {:?}", c_str);
}
}
});
unsafe {
libc::pause();
};
}