内存管理
概述
Cube Hypervisor 提供灵活的内存管理机制,支持大页、NUMA、内存热插拔等特性,满足不同场景的性能需求。
内存区域布局
x86_64 内存布局
内存区域定义
rust
// arch/src/x86_64/layout.rs
pub const RAM_START: GuestAddress = GuestAddress(0x100000000); // 4GB
pub const MEM_32BIT_RESERVED_START: GuestAddress = GuestAddress(0xC0000000); // 3GB
pub const MEM_32BIT_RESERVED_SIZE: u64 = 0x80000000; // 2GB
pub const MMIO_START: GuestAddress = GuestAddress(0x80000000); // 2GB
pub const MMIO_SIZE: u64 = 0x40000000; // 1GB
pub const IOAPIC_START: GuestAddress = GuestAddress(0xFEC00000);
pub const IOAPIC_SIZE: u64 = 0x10000;
pub const APIC_START: GuestAddress = GuestAddress(0xFEE00000);
pub const APIC_SIZE: u64 = 0x10000;MemoryManager
核心结构
rust
// vmm/src/memory_manager.rs
pub struct MemoryManager {
guest_memory: GuestMemoryMmap,
next_region_slot: u32,
zones: HashMap<String, VirtioMemZone>,
hotplug_slots: Vec<HotPlugState>,
selected_slot: usize,
dynamic: bool,
balloon: Option<Arc<Mutex<virtio_devices::Balloon>>>,
virtio_devices: Vec<Arc<Mutex<virtio_devices::Mem>>>,
shared: bool,
hugepages: bool,
hugepage_size: Option<u64>,
prefault: bool,
thp: bool,
allocator: SystemAllocator,
}内存创建流程
大页支持
大页配置
rust
// vmm/src/vm_config.rs
pub struct MemoryConfig {
pub size: u64,
pub mergeable: bool,
pub shared: bool,
pub hugepages: bool,
pub hugepage_size: Option<u64>,
pub hotplug_method: HotplugMethod,
pub hotplug_size: Option<u64>,
pub hotplugged_size: Option<u64>,
pub prefault: bool,
pub thp: bool,
// ...
}大页分配
rust
// vmm/src/memory_manager.rs
fn create_memory_region(
&mut self,
zone: &MemoryZoneConfig,
) -> Result<GuestRegionMmap> {
let size = zone.size;
if zone.hugepages {
// 使用大页分配
let hugepage_size = zone.hugepage_size.unwrap_or(2 * 1024 * 1024); // 2MB
self.allocate_hugepages(size, hugepage_size)
} else {
// 普通页分配
self.allocate_normal_pages(size)
}
}
fn allocate_hugepages(
&self,
size: u64,
hugepage_size: u64,
) -> Result<GuestRegionMmap> {
// 创建大页映射
let region = MmapRegion::new(
size as usize,
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_HUGETLB,
Some(hugepage_size),
)?;
Ok(GuestRegionMmap::new(region, GuestAddress(0)))
}大页优势
| 特性 | 普通页 (4KB) | 大页 (2MB) | 大页 (1GB) |
|---|---|---|---|
| TLB 条目 | 多 | 少 | 极少 |
| 页表开销 | 高 | 低 | 极低 |
| 缺页延迟 | 高 | 低 | 极低 |
| 适用场景 | 通用 | 内存密集型 | 大内存 |
NUMA 支持
NUMA 配置
rust
// vmm/src/vm_config.rs
pub struct NumaConfig {
pub guest_numa_nodes: Vec<GuestNumaNode>,
}
pub struct GuestNumaNode {
pub id: u32,
pub cpus: Option<Vec<u8>>,
pub distances: Option<Vec<NumaDistance>>,
pub memory_zones: Vec<String>,
}NUMA 拓扑
NUMA 绑定
rust
// vmm/src/memory_manager.rs
fn bind_to_numa_node(
&self,
region: &GuestRegionMmap,
node_id: u32,
) -> Result<()> {
// 设置内存策略
let node_mask = 1u64 << node_id;
unsafe {
libc::set_mempolicy(
MPOL_BIND,
&node_mask as *const u64,
64,
);
}
// 移动页面到目标节点
unsafe {
libc::migrate_pages(
0,
node_mask,
1 << node_id,
);
}
Ok(())
}内存热插拔
ACPI 热插拔
Virtio-mem 热插拔
热插拔实现
rust
// vmm/src/memory_manager.rs
impl MemoryManager {
pub fn hotplug_memory(
&mut self,
size: u64,
) -> Result<()> {
match self.hotplug_method {
HotplugMethod::Acpi => {
self.hotplug_memory_acpi(size)
}
HotplugMethod::VirtioMem => {
self.hotplug_memory_virtio_mem(size)
}
}
}
fn hotplug_memory_acpi(&mut self, size: u64) -> Result<()> {
// 找到空闲槽位
let slot = self.find_free_slot()?;
// 分配内存
let region = self.allocate_region(size)?;
// 映射到 Guest
self.map_region(region, slot)?;
// 发送 ACPI 通知
self.notify_acpi_hotplug(slot)?;
Ok(())
}
fn hotplug_memory_virtio_mem(&mut self, size: u64) -> Result<()> {
// 通过 virtio-mem 设备调整大小
if let Some(virtio_mem) = &self.virtio_devices.first() {
virtio_mem.lock().unwrap().resize(size)?;
}
Ok(())
}
}内存气球
Balloon 设备
Balloon 设备允许动态调整 Guest 内存使用:
Balloon 实现
rust
// virtio-devices/src/balloon.rs
pub struct Balloon {
common: VirtioCommon,
inflate_queue: Queue,
deflate_queue: Queue,
config: VirtioBalloonConfig,
stats_polling_interval: u32,
}
impl VirtioDevice for Balloon {
fn activate(&mut self, mem: GuestMemoryAtomic, ...) -> ActivateResult {
// 处理 inflate 请求(释放内存)
// 处理 deflate 请求(回收内存)
// 收集内存统计信息
Ok(())
}
}内存性能优化
1. 预分配
rust
// vmm/src/memory_manager.rs
fn allocate_with_prefault(&self, size: u64) -> Result<GuestRegionMmap> {
let region = MmapRegion::new(
size as usize,
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_POPULATE,
None,
)?;
Ok(GuestRegionMmap::new(region, GuestAddress(0)))
}2. 透明大页 (THP)
rust
// vmm/src/memory_manager.rs
fn enable_thp(&self, region: &GuestRegionMmap) -> Result<()> {
unsafe {
libc::madvise(
region.as_ptr() as *mut libc::c_void,
region.len(),
libc::MADV_HUGEPAGE,
);
}
Ok(())
}3. 内存合并
rust
// vmm/src/memory_manager.rs
fn enable_mergeable(&self, region: &GuestRegionMmap) -> Result<()> {
unsafe {
libc::madvise(
region.as_ptr() as *mut libc::c_void,
region.len(),
libc::MADV_MERGEABLE,
);
}
Ok(())
}内存配置示例
基础配置
json
{
"memory": {
"size": 536870912,
"shared": false,
"hugepages": false
}
}大页配置
json
{
"memory": {
"size": 1073741824,
"hugepages": true,
"hugepage_size": 2097152
}
}NUMA 配置
json
{
"memory": {
"size": 1073741824,
"zones": [
{
"id": "zone0",
"size": 536870912,
"host_numa_node": 0
},
{
"id": "zone1",
"size": 536870912,
"host_numa_node": 1
}
]
},
"numa": [
{
"guest_numa_nodes": [
{
"id": 0,
"memory_zones": ["zone0"]
},
{
"id": 1,
"memory_zones": ["zone1"]
}
]
}
]
}最佳实践
- 合理设置内存大小 - 根据工作负载设置,避免过度分配
- 启用大页 - 内存密集型应用启用大页
- NUMA 绑定 - 多 NUMA 节点时配置 NUMA 策略
- 使用热插拔 - 动态调整内存需求
- 启用 Balloon - 回收未使用的内存