适用于连续资源块的数组空闲链表的算法

简介:

如何来管理空闲资源,显而易见的是组织成一个双向链表,称作freelist,然后每次从该链表上取出一个,释放的时候再放回去。为了减少碎片,最好的策略就是优先分配最近释放掉的那个,如果能考虑合并的话,类似伙伴系统那样,就再好不过了,本文给出的是一个通用的可以将资源映射到一个整型ID的资源分配算法,完全基于一个数组,不需要内存管理,也不需要分配结构体。
       组织链表的时候,内存管理要耗去大量的工作,前向指针和后向指针的修改前提是必须有这些指针。典型的数据结构就是Linux内核的list_head结构体。但是对于静态的类似位图的资源并不适合用list_head来组织,因为这类资源本身可以映射到一块连续的以自然数计数的ID,比较典型的就是磁盘的空闲块,连续内存块的分配。
       既然资源位置是连续的,它就一定能用连续的自然数来表示,那么所有的资源就可以表示成一个数组了-其映射成自然数的ID的数组,记为ArrayA。
       接下来我们需要另外一个数组来表示空闲链表,记为ArrayB。
       接下来的然后,就是构造ArrayB了...ArrayB的大小等于ArrayA大小加上1,多出来的这个元素可以作为不动点存在,它是不会被分配出去的。ArrayB的元素的大小是ArrayA数组大小占据字节数的两倍,是为了在一个元素中存储两个INDEX,比如数组大小可以用8位数据表示,即最多256个元素,那么ArrayB的元素就应该是2*8这么大的,举例说明:
数组大小:short-最多65536个元素
ArrayA的数组定义:int arrayA[MAX];MAX最大65536
ArrayB的数组定义:int arrayB[];int型为两个short型
结构体形象化表示ArrayB:

1
2
3
4
5
6
#define NUM    8
struct  freeHL {
         short  high_preindex;  //表示前一个ArrayA数组中索引
         short  low_nextindex;   //表示后一个ArrayA数组中索引
};
struct  freeHL  freelist[NUM+1];

相当于将ArrayB劈开成了两半。
然后就可以在连续的数组空间进行链接操作了。实际上这个数组表示的freelist和指针表示的prev,next的freelist是一致的,数组下标也是一个指针,只是在数组表示的freelist中,使用的是相对指针偏移而已,表示为下标!
       下面就是一个算法实现问题了,很简单。在freelist中分配了一个index后,需要修改其前向index的后向index以及后向index的前向index,释放过程和分配过程相反。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
short  data[NUM];  //是为ArrayA
struct  freeHL  freelist[NUM+1]; /是为ArrayB
//表示一个下一个分配的index;
unsigned  int  position = 0;
//全局的一次性初始化,注意,如果是序列化到了文件,
//则不能再次初始化了,应该从文件反序列化来初始化。
void  list_init()
{
         int  i = 0, j = -1;
         for  (; i < NUM+1; i++) {
                 freelist[i].high_preindex = (i + NUM)%(NUM+1);
                 freelist[i].low_nextindex = (i + 1)%(NUM+1);
         }
         position = 0;
}
//分配接口
int  nalloc()
{
         int  ret_index = -1, next_index = -1, pre_index = -1;
         ret_index = position;
     //保存当前要分配index的前向index
         next_index = freelist[position].low_nextindex;
     //保存当前要分配index的后向index
         pre_index = freelist[position].high_preindex;
     //分配当前index
         position = next_index;
         if  (ret_index == next_index) {
                 return  -1;
         }
     //更新当前index前向index的后向index
         freelist[freelist[ret_index].high_preindex].low_nextindex = next_index;
     //更新当前index后向index的前向index
         freelist[freelist[ret_index].low_nextindex].high_preindex = pre_index;
         return  ret_index;
}
//释放接口
int  nfree(unsigned  int  id)
{
         int  pos_pre = -1, pos_next = -1;
     //保存下一个要分配的index的前向index,减少碎片以及更加容易命中cache
         pos_pre = freelist[position].high_preindex;
     //释放index为id的元素
         freelist[pos_pre].low_nextindex = id;
         freelist[id].high_preindex = pos_pre;
         freelist[id].low_nextindex = position;
     //下一个要分配的index为刚释放的index
         position = id;
}

下面是一个测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int  main( int  argc,  char  **argv)
{
         list_init();
         int  i = 0;
         printf ( "begin\n" );
         for  (; i < NUM+1; i++) {
                 printf ( "\n%d \n" , nalloc());
         }
         nfree(5);
         nfree(0);
         nfree(7);
         for  (i = 0; i < NUM+1; i++) {
                 printf ( "\n%d \n" , nalloc());
         }
         printf ( "\nend\n" );
}

这个代码用在何处呢?前面说过,用在资源可以表示为连续ID的场合,这种场合何在?在《编写一个UNIX文件系统》中,我说那个空闲i节点以及空闲块的分配算法不好,而上述的方法就可以用,效果比较好,也就是说,将一点点的工作施放于每次分配/释放的时候,就可以避免在某个时间点做大量的积攒下来的繁重的工作。这个算法省去了遍历操作,代价就是占用了一点连续的地址空间。


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1282347


相关文章
|
10月前
|
存储 监控 算法
电脑监控管理中的 C# 哈希表进程资源索引算法
哈希表凭借O(1)查询效率、动态增删性能及低内存开销,适配电脑监控系统对进程资源数据的实时索引需求。通过定制哈希函数与链地址法冲突解决,实现高效进程状态追踪与异常预警。
372 10
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
658 30
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
949 25
|
存储 人工智能 算法
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
1031 23
|
存储 监控 算法
员工电脑监控系统中的 C# 链表算法剖析-如何监控员工的电脑
当代企业管理体系中,员工电脑监控已成为一个具有重要研究价值与实践意义的关键议题。随着数字化办公模式的广泛普及,企业亟需确保员工对公司资源的合理利用,维护网络安全环境,并提升整体工作效率。有效的电脑监控手段对于企业实现这些目标具有不可忽视的作用,而这一过程离不开精妙的数据结构与算法作为技术支撑。本文旨在深入探究链表(Linked List)这一经典数据结构在员工电脑监控场景中的具体应用,并通过 C# 编程语言给出详尽的代码实现与解析。
305 5
|
存储 监控 算法
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
268 7
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
350 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
305 0
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
605 5
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!