忽然,面前的空间展开,化成一张巨大的、向四面八方无尽延伸的方格纸。
每一个小格子代表一个內存单元,被占用的、空閒的都一一陈列於此。
它们都在等待创造者的规划安排。
前提是你能在它们服从秩序之前,保证自己不被混乱击穿大脑。
“这就是你的画布,孩子。b语言没能征服它,我们来试试。”
里奇的声音从身后的虚空中传来,李林定了定心神。
动手。
首先要解决“我是谁”的问题。
每一个分配出去的內存块,它必须知道自己多大、属於谁、下一个是谁。
李林开始用struct定义內存块的头部信息,包括块的大小、是否空閒和炼表指针。
他在方格纸上画下第一道箭头,从一块內存的头部指向下一块,再指向下一块,把那些散落的格子串成一条链。
由此,他便实现了最基础的alloc和free。
遍歷炼表,找到第一块足够大的空閒块,分配出去,释放时標记为空閒,和相邻的空閒块合併。
方格纸上,逐渐开始有了秩序。
“太慢了。”
里奇的声音再次响起,这次带著毫不掩饰的失望,
“每次分配都要从头遍歷,这在系统內核里根本不能用。你这个版本比那些老古董手写的汇编还要差。”
李林盯著方格纸上那条长长的炼表。
是啊,所以需要一些新东西了。
李林握了握拳头,闭上眼睛,回想起这些天来自己的所学所思。
首先,他想到的是自己在现代编程中见过的——
內存对齐技术。
对齐到2的冪次,用地址本身来编码信息。
再结合之前胡云程提过的“细胞”,两个思路撞在一起,解法也就应运而生了。
伙伴算法。
將內存按2的冪次分割成块。
当请求来临,找到刚好大於等於请求大小的块。
如果块太大,就一分为二,“伙伴对伙伴”,直到大小合適。
回收的时候,检查伙伴是否也空閒,如果是就合併回去。
最关键的是,计算伙伴地址不需要遍歷,不需要查表。
只需要一次位运算。
於是,李林在方格纸上重新画了一遍。
这次不再是长长的炼表,而是一棵二叉树。
每个节点都有它的伙伴,每个伙伴都在一个固定的位置上等它。
他用位运算代替了浮点和除法,用地址本身作为定位伙伴的坐標。