我正在编写一个内存分配器,它由位图(uint8_t
数组)支持当前当分配请求出现时我将位图从0位扫描到n位并搜索可以满足的空间请求。 (位1表示使用0表示页面的页面是免费的)现在,不是一次一位地搜索空格,是否有技术可以更快地扫描整个阵列?即如果有3页内存请求到达,我想在一次搜索中一次性搜索000
模式而不进行循环?
PS:我没有使用std::bitset
,因为它不适用于我正在使用的编译器。 AFAIK也不允许我搜索多个位。
编辑:比特被打包成字节,一个uint8_t
有8页(每比特1个)编码。
答案 0 :(得分:1)
要扫描一个空页,您可以一次遍历位数一个完整字节并检查它是否小于255.如果它小于,则至少有一个零位。更好的方法是一次扫描32位或64位(无符号整数),然后缩小uint内的搜索范围。
要优化一位,您可以用零位跟踪第一个字节(并在释放页面时更新该位置)。一旦分配了这个空闲页面,这可能会产生误报,但至少下次扫描可以从那里开始而不是在开始时。
如果您愿意在功率为2的情况下对齐较大的块(取决于您的数据结构),则可以优化对多个页面的扫描。例如,要分配8个页面,您只需扫描整个字节为零:
1 page: scan for any zero bit (up to 64 bits at a time)
2 pages: scan for 2 zero bits at bit position 0,2,4,6
3-4 pages: scan for zero nibble (for 3 pages, the fourth would be available for 1 page then)
5-8 pages: scan for an empty byte
for each of the above, you could first scan 64 bits at a time.
这样,您就不必担心(或检查)byte / uint32 / uint64边界处的重叠零范围。
对于每种类型,可以保留/更新第一个空闲块的起始位置。
答案 1 :(得分:1)
不是你问题的完整答案(我想),但我希望以下功能可以提供帮助。
template <typename I>
bool scan_n_zeros (I iVal, std::size_t num)
{
while ( --num )
iVal |= ((iVal << 1) | I{1});
return iVal != I(-1);
}
它返回(如果我已正确写入)true
如果(不在哪里)num
中至少有iVal
个连续的零位。
以下是T
为uint8_t
#include <iostream>
template <typename I>
bool scan_n_zeros (I iVal, std::size_t num)
{
while ( --num )
iVal |= ((iVal << 1) | I{1});
return iVal != I(-1);
}
int main()
{
uint8_t u0 { 0b00100100 };
uint8_t u1 { 0b00001111 };
uint8_t u2 { 0b10000111 };
uint8_t u3 { 0b11000011 };
uint8_t u4 { 0b11100001 };
uint8_t u5 { 0b11110000 };
std::cout << scan_n_zeros(u0, 2U) << std::endl; // print 1
std::cout << scan_n_zeros(u0, 3U) << std::endl; // print 0
std::cout << scan_n_zeros(u1, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u1, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u2, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u2, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u3, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u3, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u4, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u4, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u5, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u5, 5U) << std::endl; // print 0
}