NetBSD 内存管理系统 UVM 浅析
2006-08-09 22:57:02 来源:WEB开发网这种两层 (三层) 指向的机制是复杂的, 一个更严重的问题是, vm_object 在使用时有一个 cache, 而系统被设计成资源对象与内存系统完全分离, 像 vnode 对象它又由另一个 cache 系统缓存, 这样不但降低了内存的使用率, 还会产生一致性问题. (XXX: Really?)
所以 UVM 决定把 uvm_obj 直接嵌入可映射入内存的资源对象中, 如 vnode 结构中就有 uvm_obj 项, 来解决这种复杂性和不一致. 大大简化了对象操作.
Anonymous Memory Object
Anonymous Memory Object 是指没有文件与之相联系的内存对象, 因此是无名 (anonymous) 的, 它在初次使用时为空(填为 0), 用完后被自动抛弃. (XXX: 我们是否可以在概念上把它看成 /dev/zero 的映射?)
XXX: 管理算法, uao_get(), uao_put() 解析.
解决 COW: UVM 方法
COW (Copy-On-Write) 是一个重要的系统特性, 为 fork(2), mmap(2) 等重要的系统调用提供了强力支持.
4.4BSD 使用影子(shadow)对象的方法解决 COW 的问题. 当拷贝内存的时候, 目标地址所对应的是一个影子对象, 它指向原对象作为后援对象, 当由于写操作产生一个 fault 的时候, 就从后援对象那里获取数据, 完成 COW. 注意影子对象也可以被复制, 成为另一个影子对象的后援对象, 这样就成为了一个影子对象链 .
使用这样的方法, 当影子对象链太长的时候, 处理 fault 的时间就会很长, 因为要整条影子对象链都 fault 一次. 偏偏使用 COW 肯定会产生很多 fault, 因此会产生严重的效率问题. 一种解决方法是在可能的时候尽量压缩影子对象链 (FreeBSD 方法), 这增加了复杂性却又没有真正解决问题.
UVM 使用了 amap 来解决 COW. amap 管理一组 anon, 每个 anon 指向一个 vm_page, 每个 anon 都有一个引用数, 引用数大于 1 时会使之不可写. 当我们要 COW copy 一个没有 amap 的 entry 时, 我们将两者都标为 UVM_ET_NEEDSCOPY, 这时候, 只要对其作写操作就会 fault, 而 fault 处理发 现它们时 NEEDSCOPY 的时候, 就会为其简历 amap, 以后的写操作都写在 amap 上, 达到了 COW 的目的; 而要 COW copy 一个带 amap 的entry 时, 我们还要复制 amap, 新 entry 就能访问与旧 entry 一样的数据, 这样以来, 原 amap 所管理的 anon 的引用数就变成 2, 而变成只读. 因此, 对其写操作也会引起 fault, 这是系统将申请一个 anon 和新页, 复制页面数据, 将 anon 连入被写的 amap, 也就完成了 COW. 这样看来, 无论是首次 COW, 还是 COW 对象上的 COW 我们都可以用上述机制处理. 而只要访问两层的接口, 避免了长影子对象链的问题, 又简化了设计. 其关键就在于 COW 时我们能够 复制 而不是 引用 amap, 相对于 COW 对象的 fault, 复制 amap 出现的概率小得多, 因此复制整个 amap 是有价值的.
更多精彩
赞助商链接