zone.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. //! A ZoneAllocator to allocate arbitrary object sizes (up to `ZoneAllocator::MAX_ALLOC_SIZE`)
  2. //!
  3. //! The ZoneAllocator achieves this by having many `SCAllocator`
  4. use crate::*;
  5. /// Creates an instance of a zone, we do this in a macro because we
  6. /// re-use the code in const and non-const functions
  7. ///
  8. /// We can get rid of this once the const fn feature is fully stabilized.
  9. macro_rules! new_zone {
  10. () => {
  11. ZoneAllocator {
  12. // TODO(perf): We should probably pick better classes
  13. // rather than powers-of-two (see SuperMalloc etc.)
  14. small_slabs: [
  15. SCAllocator::new(1 << 3), // 8
  16. SCAllocator::new(1 << 4), // 16
  17. SCAllocator::new(1 << 5), // 32
  18. SCAllocator::new(1 << 6), // 64
  19. SCAllocator::new(1 << 7), // 128
  20. SCAllocator::new(1 << 8), // 256
  21. SCAllocator::new(1 << 9), // 512
  22. SCAllocator::new(1 << 10), // 1024
  23. SCAllocator::new(1 << 11), // 2048 ],
  24. ],
  25. total: 0,
  26. }
  27. };
  28. }
  29. /// A zone allocator for arbitrary sized allocations.
  30. ///
  31. /// Has a bunch of `SCAllocator` and through that can serve allocation
  32. /// requests for many different object sizes up to (MAX_SIZE_CLASSES) by selecting
  33. /// the right `SCAllocator` for allocation and deallocation.
  34. ///
  35. /// The allocator provides to refill functions `refill` and `refill_large`
  36. /// to provide the underlying `SCAllocator` with more memory in case it runs out.
  37. pub struct ZoneAllocator<'a> {
  38. small_slabs: [SCAllocator<'a, ObjectPage<'a>>; ZoneAllocator::MAX_BASE_SIZE_CLASSES],
  39. total: u64,
  40. }
  41. impl<'a> Default for ZoneAllocator<'a> {
  42. fn default() -> ZoneAllocator<'a> {
  43. new_zone!()
  44. }
  45. }
  46. enum Slab {
  47. Base(usize),
  48. Unsupported,
  49. }
  50. impl<'a> ZoneAllocator<'a> {
  51. /// Maximum size which is allocated with ObjectPages (4 KiB pages).
  52. ///
  53. /// e.g. this is 4 KiB - 80 bytes of meta-data.
  54. pub const MAX_BASE_ALLOC_SIZE: usize = 1 << 11;
  55. /// How many allocators of type SCAllocator<ObjectPage> we have.
  56. pub const MAX_BASE_SIZE_CLASSES: usize = 9;
  57. #[cfg(feature = "unstable")]
  58. pub const fn new() -> ZoneAllocator<'a> {
  59. new_zone!()
  60. }
  61. #[cfg(not(feature = "unstable"))]
  62. pub fn new() -> ZoneAllocator<'a> {
  63. new_zone!()
  64. }
  65. /// Return maximum size an object of size `current_size` can use.
  66. ///
  67. /// Used to optimize `realloc`.
  68. pub fn get_max_size(current_size: usize) -> Option<usize> {
  69. match current_size {
  70. 0..=8 => Some(8),
  71. 9..=16 => Some(16),
  72. 17..=32 => Some(32),
  73. 33..=64 => Some(64),
  74. 65..=128 => Some(128),
  75. 129..=256 => Some(256),
  76. 257..=512 => Some(512),
  77. 513..=1024 => Some(1024),
  78. 1025..=2048 => Some(2048),
  79. _ => None,
  80. }
  81. }
  82. /// Figure out index into zone array to get the correct slab allocator for that size.
  83. fn get_slab(requested_size: usize) -> Slab {
  84. match requested_size {
  85. 0..=8 => Slab::Base(0),
  86. 9..=16 => Slab::Base(1),
  87. 17..=32 => Slab::Base(2),
  88. 33..=64 => Slab::Base(3),
  89. 65..=128 => Slab::Base(4),
  90. 129..=256 => Slab::Base(5),
  91. 257..=512 => Slab::Base(6),
  92. 513..=1024 => Slab::Base(7),
  93. 1025..=2048 => Slab::Base(8),
  94. _ => Slab::Unsupported,
  95. }
  96. }
  97. /// Reclaims empty pages by calling `dealloc` on it and removing it from the
  98. /// empty lists in the [`SCAllocator`].
  99. ///
  100. /// The `dealloc` function is called at most `reclaim_base_max` times for
  101. /// base pages, and at most `reclaim_large_max` for large pages.
  102. pub fn try_reclaim_base_pages<F>(&mut self, mut to_reclaim: usize, mut dealloc: F)
  103. where
  104. F: Fn(*mut ObjectPage),
  105. {
  106. for i in 0..ZoneAllocator::MAX_BASE_SIZE_CLASSES {
  107. let slab = &mut self.small_slabs[i];
  108. // reclaim的page数
  109. let just_reclaimed = slab.try_reclaim_pages(to_reclaim, &mut dealloc);
  110. self.total -= (just_reclaimed * OBJECT_PAGE_SIZE) as u64;
  111. to_reclaim = to_reclaim.saturating_sub(just_reclaimed);
  112. if to_reclaim == 0 {
  113. break;
  114. }
  115. }
  116. }
  117. /// 获取scallocator中的还未被分配的空间
  118. pub fn free_space(&mut self) -> u64 {
  119. // 记录空闲空间
  120. let mut free = 0;
  121. // 遍历所有scallocator
  122. for count in 0..ZoneAllocator::MAX_BASE_SIZE_CLASSES {
  123. // 获取scallocator
  124. let scallocator = &mut self.small_slabs[count];
  125. // 遍历scallocator中的部分分配的page(partial_page)
  126. for slab_page in scallocator.slabs.iter_mut() {
  127. // 剩余可分配object数乘上page中规定的每个object的大小,即空闲空间
  128. free += slab_page.free_obj_count() * scallocator.size();
  129. }
  130. // 遍历scallocator中的empty_page,把空页空间也加上去
  131. free +=
  132. scallocator.empty_slabs.elements * (scallocator.obj_per_page * scallocator.size());
  133. }
  134. free as u64
  135. }
  136. pub fn usage(&mut self) -> SlabUsage {
  137. let free_num = self.free_space();
  138. SlabUsage::new(self.total, free_num)
  139. }
  140. }
  141. unsafe impl<'a> crate::Allocator<'a> for ZoneAllocator<'a> {
  142. /// Allocate a pointer to a block of memory described by `layout`.
  143. fn allocate(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocationError> {
  144. match ZoneAllocator::get_slab(layout.size()) {
  145. Slab::Base(idx) => self.small_slabs[idx].allocate(layout),
  146. Slab::Unsupported => Err(AllocationError::InvalidLayout),
  147. }
  148. }
  149. /// Deallocates a pointer to a block of memory, which was
  150. /// previously allocated by `allocate`.
  151. ///
  152. /// # Arguments
  153. /// * `ptr` - Address of the memory location to free.
  154. /// * `layout` - Memory layout of the block pointed to by `ptr`.
  155. /// * `slab_callback` - The callback function to free slab_page in buddy.
  156. unsafe fn deallocate(
  157. &mut self,
  158. ptr: NonNull<u8>,
  159. layout: Layout,
  160. slab_callback: &'static dyn CallBack,
  161. ) -> Result<(), AllocationError> {
  162. match ZoneAllocator::get_slab(layout.size()) {
  163. Slab::Base(idx) => self.small_slabs[idx].deallocate(ptr, layout, slab_callback),
  164. Slab::Unsupported => Err(AllocationError::InvalidLayout),
  165. }
  166. }
  167. /// Refills the SCAllocator for a given Layout with an ObjectPage.
  168. ///
  169. /// # Safety
  170. /// ObjectPage needs to be emtpy etc.
  171. unsafe fn refill(
  172. &mut self,
  173. layout: Layout,
  174. new_page: &'a mut ObjectPage<'a>,
  175. ) -> Result<(), AllocationError> {
  176. match ZoneAllocator::get_slab(layout.size()) {
  177. Slab::Base(idx) => {
  178. self.small_slabs[idx].refill(new_page);
  179. // 每refill一个page就为slab的总空间统计加上4KB
  180. self.total += OBJECT_PAGE_SIZE as u64;
  181. Ok(())
  182. }
  183. Slab::Unsupported => Err(AllocationError::InvalidLayout),
  184. }
  185. }
  186. }
  187. /// Slab内存空间使用情况
  188. pub struct SlabUsage {
  189. // slab总共使用的内存空间
  190. total: u64,
  191. // slab的空闲空间
  192. free: u64,
  193. }
  194. impl SlabUsage {
  195. /// 初始化SlabUsage
  196. pub fn new(total: u64, free: u64) -> Self {
  197. Self { total, free }
  198. }
  199. pub fn total(&self) -> u64 {
  200. self.total
  201. }
  202. pub fn used(&self) -> u64 {
  203. self.total - self.free
  204. }
  205. pub fn free(&self) -> u64 {
  206. self.free
  207. }
  208. }