当前位置: 首页 > news >正文

Linux内核bitmap组件详解

1. 引言

在Linux内核开发中,bitmap(位图)是一种极为常用的数据结构。它以紧凑的方式用一组二进制位(bit)来表示大量的布尔状态,广泛应用于资源分配、状态管理、权限控制等场景。Linux内核为bitmap的操作提供了高效、丰富的API,主要实现位于bitmap.c和bitmap.h。本文将系统性地介绍内核bitmap组件的功能、设计思想、核心实现、典型应用及其优化策略,帮助读者深入理解其原理与工程价值。记得刚参加工作那会,傻傻的在那里自己造轮子,果然开源linux才是最大的宝藏来源。

2. bitmap的基本概念与应用场景

2.1 基本概念

bitmap是一种用一组连续的bit位来表示集合元素状态的数据结构。每一位(bit)可以表示一个对象的“有/无”、“占用/空闲”、“允许/禁止”等二值状态。与数组、链表等结构相比,bitmap在存储空间和操作效率上具有显著优势,尤其适合大规模、稀疏、二值状态的场景。

2.2  典型应用场景

  • 物理/虚拟内存页管理(页帧分配器)

  • 进程PID分配

  • 文件系统inode、block分配

  • 设备资源分配(如PCI中断号、DMA通道)

  • 权限掩码、状态标记

  • 任务调度、CPU亲和性掩码

3. bitmap的内核实现结构

在内核中,bitmap通常用unsigned long数组实现,每个unsigned long包含若干bit(32位或64位,取决于平台)。头文件include/linux/bitmap.h定义了相关类型和宏:

typedef unsigned long *bitmap_t;
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define BITMAP_LAST_WORD_MASK(nbits) ...
  • BITS_TO_LONGS(bits) 计算需要多少个 unsigned long 才能容纳 bits 个 bit。例如,100 位 bitmap 在 64 位系统上需要 2 个 unsigned long

bitmap的分配有两种方式:

  • 静态分配:如DECLARE_BITMAP(name, nbits),适用于编译期已知大小的场景。

  • 动态分配:如bitmap_zalloc(nbits, gfp_flags),适用于运行时动态需求。

释放时使用bitmap_free()

4. bitmap 的核心 API 及实现

4.1 基本操作

4.1.1 bitmap_zero

将 bitmap 的所有位清零。

static inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
{if (small_const_nbits(nbits))*dst = 0UL;else {memset(dst, 0, bitmap_size(nbits));}
}
  • 对小型 bitmap 直接赋值,大型 bitmap 用 memset

4.1.2 bitmap_fill

将 bitmap 的所有位置为 1。

static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
{unsigned int nlongs = BITS_TO_LONGS(nbits);if (!small_const_nbits(nbits)) {unsigned int len = (nlongs - 1) * sizeof(unsigned long);memset(dst, 0xff,  len);}dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
}
  • 先将所有 unsigned long 填满,再处理最后一个 long 的多余位。

4.1.3 bitmap_set / bitmap_clear

批量置位或清零指定区间的 bit。

static inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits)
{if (__builtin_constant_p(nbits) && nbits == 1)__set_bit(start, map);else if (small_const_nbits(start + nbits))*map |= GENMASK(start + nbits - 1, start);else__bitmap_set(map, start, nbits);
}
  • 对单个位或小范围优化,批量操作调用底层实现。

4.1.4 bitmap_and / bitmap_or / bitmap_equal 

支持集合的与、或、等于等操作。

static inline bool bitmap_and(unsigned long *dst, const unsigned long *src1,const unsigned long *src2, unsigned int nbits)
{if (small_const_nbits(nbits))return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0;return __bitmap_and(dst, src1, src2, nbits);
}
  • 对小型 bitmap 直接操作,大型 bitmap 调用循环实现。

4.1.5 bitmap_weight

统计 bitmap 中 1 的个数(即集合大小)。

static inline unsigned int bitmap_weight(const unsigned long *src, unsigned int nbits)
{if (small_const_nbits(nbits))return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));return __bitmap_weight(src, nbits);
}

4.1.6 bitmap_empty / bitmap_full

判断 bitmap 是否全为 0 或全为 1。

static inline bool bitmap_empty(const unsigned long *src, unsigned int nbits)
{if (small_const_nbits(nbits))return ! (*src & BITMAP_LAST_WORD_MASK(nbits));return find_first_bit(src, nbits) == nbits;
}

4.1.7 bitmap_alloc / bitmap_zalloc / bitmap_free

动态分配、清零分配和释放 bitmap。

static inline unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags)
{return malloc(bitmap_size(nbits));
}
static inline unsigned long *bitmap_zalloc(int nbits)
{return calloc(1, bitmap_size(nbits));
}
static inline void bitmap_free(unsigned long *bitmap)
{free(bitmap);
}

4.2 进阶操作

4.2.1 bitmap_scnprintf

将 bitmap 以字符串形式输出,便于调试和日志。

size_t bitmap_scnprintf(unsigned long *bitmap, unsigned int nbits,char *buf, size_t size);
  • 输出如 "0-3,5,7-9",表示哪些 bit 被置位。

4.2.3 bitmap_intersects

判断两个 bitmap 是否有交集。

static inline bool bitmap_intersects(const unsigned long *src1,const unsigned long *src2,unsigned int nbits)
{if (small_const_nbits(nbits))return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;elsereturn __bitmap_intersects(src1, src2, nbits);
}

5. bitmap 的性能优化

5.1 小型 bitmap 优化

  • 对于 bit 数较少的 bitmap,直接用单个 unsigned long 操作,避免循环和函数调用。

  • 利用编译器内建函数(如 __builtin_constant_p)优化常量场景。

5.2 批量操作优化

  • 对齐到字节/字长边界时,直接用 memsetmemcpy 批量处理。

  • 对于大 bitmap,可用 SIMD 指令(如 AVX2/NEON)进一步加速。

5.3 查找优化

  • 利用硬件指令(如 x86 的 BSF/POPCNT)加速查找第一个 1/0、统计 1 的个数。

  • 对于稀疏 bitmap,可用跳表、哈希等高级结构进一步优化。

6. 总结与最佳实践

  • bitmap 是 Linux 内核和驱动开发中不可或缺的高效集合管理工具。

  • 通过位操作、批量处理、查找优化等手段,bitmap 能高效支持大规模对象的分配、回收、集合运算等需求。

  • 合理选择 bitmap 大小、对齐方式、操作 API,可进一步提升性能和可维护性。

  • 在多核/并发场景下,注意使用原子位操作,避免竞态条件。

  • 善用 bitmap_scnprintf、for_each_set_bit 等辅助工具,提升调试和开发效率。

http://www.dtcms.com/a/353866.html

相关文章:

  • 给Ubuntu添加新用户
  • MyBatis 之关联查询(一对一、一对多及多对多实现)
  • Ansible Playbook 概述与实践案例(下)
  • 基于muduo库的图床云共享存储项目(二)
  • STM32 之串口WIFI应用--基于RTOS的环境
  • AlphaFold 2 本地部署与安装教程(Linux)
  • ICCV 2025 | 清华IEDA提出GUAVA,单图创建可驱动的上半身3D化身!实时、高效,还能捕捉细腻的面部表情和手势。
  • 【51单片机】【protues仿真】基于51单片机篮球计时计分器数码管系统
  • 什么是代理ip?代理ip的运作机制
  • C++ 中 ::(作用域解析运算符)的用途
  • 大小鼠糖水偏爱实验系统 糖水偏好实验系统 小鼠糖水偏好实验系统 大鼠糖水偏好实验系统
  • 【半导体制造流程概述】
  • 优化IDEA卡顿的问题
  • 使用CCProxy搭建http/https代理服务器
  • AWS OpenSearch 可观测最佳实践
  • Maya绑定:人物绑定详细案例
  • 数据结构之 【红黑树的简介与插入问题的实现】
  • 数值分析离散积分近似求值
  • 【数据分析】微生物群落网络构建与模块划分的比较研究:SparCC、Spearman-RAW与Spearman-CLR方法的性能评估
  • Shell编程-随机密码生成
  • volitale伪共享问题及解决方案
  • SoC如何实现线程安全?
  • 【进阶篇第五弹】《详解存储过程》从0掌握MySQL中的存储过程以及存储函数
  • TypeScript:Interface接口
  • 如何启动一个分支网络改造试点?三步走
  • 【链表 - LeetCode】25. K 个一组翻转链表
  • 干眼症护理学注意事项
  • linux下的网络编程(2)
  • 技术分析 | Parasoft C/C++test如何突破单元测试的隔离难题
  • 亚马逊关键词策略全解析:类型、工具与多账号运营优化指南