Skip to content

内存管理

概述

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"]
        }
      ]
    }
  ]
}

最佳实践

  1. 合理设置内存大小 - 根据工作负载设置,避免过度分配
  2. 启用大页 - 内存密集型应用启用大页
  3. NUMA 绑定 - 多 NUMA 节点时配置 NUMA 策略
  4. 使用热插拔 - 动态调整内存需求
  5. 启用 Balloon - 回收未使用的内存

下一步