FreeBSD zone allocator

  FreeBSD zone allocator 实现为一个 slab allocator ,但在细节方面和原始的 slab allocator 不太一样。

 

  在 zone allocator 中,keg 充当着 back end 的角色,zone 起着 front end 的作用。

   主要的数据结构有:struct uma_keg , struct uma_zone , struct uma_slab , struct uma_cache , struct uma_bucket。

 

 

  keg 存储着三类 slab 的链表:uk_free_slab(完全没有使用的 slab ),uk_part_slab(部分使用的 slab),uk_full_slab(全部使用了的 slab)。uk_link链表连接这系统中所有的 keg ,链表头存储在 uma_kegs中,以便 zone_foreach 遍历所有的 keg。

  us_link 连接着所有属于同类的 slab ,当用 uma_large_malloc 分配时,slab 不被 keg 管理,用 us_size 保存数据的大小。

  当分配内存时,首先检查当前 CPU 的 uc_freebucket 和 uc_allocbucket 是否有缓存的 item;当释放内存时,首先检查当前 CPU 的 uc_freebucket 和 uc_allocbucket 是否有空槽可以缓存释放的 item。uc_allocs 和 uc_frees 保存着迄今为止只在 cache 内进行的分配和释放数。

 

  uz_full_bucket 链表连接着所有缓存着 item 的 bucket ,uz_free_bucket 链表连接着所有没有缓存着 item 的 bucket。分配内存时,如 CPU 的 cache 内没有缓存的 item 时,可将 uz_full_bucket 链表中的 bucket 移到 CPU 的 cache 内以分配内存;释放内存时,如 CPU 的 cache 内没有空槽可以缓存释放的 item ,可将 uz_free_bucket 链表中的bucket 移到 CPU 的 cache 内以缓存内存。


  对 keg 进行 grow 操作的主要函数有:uma_zone_slab,slab_zalloc。

 

 

 

 

  uma_zone_slab 函数返回没有全部使用了的 slab 。如果调用 uma_zone_slab 时,keg 的 uk_free 为0(此时,uk_free_slab 和 uk_part_slab 链表均为空),则调用 slab_zalloc 分配新的 slab 。slab_zalloc 通过调用 keg->uk_allocf来分配 item 块内存,根据 keg->uk_flag 的标识来决定 slab 是从 keg->uk_slabzone 中分配还是存储在 item 块的最后面。如果,slab_zalloc 分配 item 块成功,keg->uk_pages 将增加 keg->uk_ppera 。当对相同的 keg 调用 uma_zone_slab 时,如果 uk_free 为 0,当 uk_maxpages 设置并且 uk_pages 大于等于 uk_maxpages 时,函数将阻塞在 uk_lock 上(见 uma_zone_slab 1977-2005行)。

  uma_zalloc_arg 函数从 zone 分配 item 。

  uma_zalloc_arg 首先尝试从当前 CPU cache 中分配 item 。如失败:若 zone 的 uz_full_bucket 链表不为空,则将其首元素移到 CPU cache 中以供分配;否则调用 uma_zalloc_bucket 装填一个新的 bucket ,并将之插入 uz_full_bucket 链表。如果 uma_zalloc_bucket 也失败,则调用 uma_zalloc_internal 分配内存。

  uma_zalloc_internal 函数先调用 uma_zone_slab 函数返回一个未用完的 slab ,再调用 uma_slab_alloc 函数从这个 slab 中分配一个 item 。uma_zone_slab 函数假设调用程序至少从返回的 slab 里分配一个 item ,所以如果返回的 slab 是完全没有使用的,则在返回之前将之从 uk_free_slab 中移除,并插入 uk_part_slab 。uma_slab_alloc 函数假设 slab 是部分使用了的 slab ,所以只处理当 slab->us_freecount 等于 0 的情况。

  

  uma_zfree_arg 将从 zone 分配的 item 返回给 zone 。

  uma_zfree_arg 与 uma_zalloc_arg 类似,首先尝试将 item 缓存在 当前 CPU cache 中。如失败:若 uz_free_bucket 链表不为空,则将其首元素移到 CPU cache 中以缓存 item ;否则,调用 bucket_alloc 分配一个空的 bucket ,并将之插入 uz_free_bucket 链表。如果 bucket_alloc 也失败,则调用 uma_zfree_internal 释放 item 。不过 uma_zfree_arg 在进行这些动作之前,先检查 keg 的可分配页面数是否达到上限,如是,则直接调用 uma_zfree_internal 释放 item ,因为 uma_zfree_internal 检查 keg 的可分配页面数是否已经降到上限数下了,并可唤醒阻塞在 keg 上的线程。

  

  zone_drain 函数通过调用 bucket_cache_drain 将 zone 中的 uz_full_bucket 缓存的 item 返还给 keg (CPU cache 中的 item 不返还),并释放 uz_full_bucket 和 uz_free_bucket 连接的所有 bucket,再将 keg 用 uk_free_slab 连接起来的 pages 释放给系统。

  zone_foreach 对系统中所有被 uma_kegs 连接的 zone 调用 zfunc 函数。

  uma_reclaim 回收所有暂且不会被使用的页面,这个函数只能被 page out daemon 调用。

 

参考文章:

  • Jeff Bonwick, The Slab Allocator: An Object-Caching Kernel Memory Allocator (1994)
  • FreeBSD zone(9) manual page
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值