<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>内存分配 on 大飞的博客</title>
    <link>https://www.dafei.me/tags/%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D/</link>
    <description>Recent content in 内存分配 on 大飞的博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Wed, 06 May 2026 08:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.dafei.me/tags/%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>从零写OS（八）：堆分配器，内核的 malloc</title>
      <link>https://www.dafei.me/posts/os-08-heap/</link>
      <pubDate>Wed, 06 May 2026 08:00:00 +0000</pubDate>
      <guid>https://www.dafei.me/posts/os-08-heap/</guid>
      <description>&lt;p&gt;PMM 负责整页分配，每次给你 4KB。但内核里经常需要分配几十、几百字节的小块——存一个结构体、一条字符串。每次都要一整页，太浪费。&lt;/p&gt;
&lt;p&gt;这一章实现 &lt;code&gt;kmalloc&lt;/code&gt; / &lt;code&gt;kfree&lt;/code&gt;：按需分配任意大小的内存块，用完归还，可以复用。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;设计空闲链表&#34;&gt;设计：空闲链表&lt;/h2&gt;
&lt;p&gt;最经典的堆实现：&lt;strong&gt;空闲链表&lt;/strong&gt;（Free List）。&lt;/p&gt;
&lt;p&gt;在堆空间里，每块内存前面加一个&lt;strong&gt;块头&lt;/strong&gt;（header）记录元数据，所有块串成双向链表：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; block {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;      size;     &lt;span style=&#34;color:#75715e&#34;&gt;// 这块数据区的大小（不含 header 本身）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt;       is_free;  &lt;span style=&#34;color:#75715e&#34;&gt;// 1=空闲，0=已分配
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; block &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;next;     &lt;span style=&#34;color:#75715e&#34;&gt;// 链表后继
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; block &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;prev;     &lt;span style=&#34;color:#75715e&#34;&gt;// 链表前驱
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;block_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内存布局长这样：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[block_t header | ← size → 数据区 ][block_t header | ← size → 数据区 ] ...
 ↑                                   ↑
 kmalloc 返回这个指针之前的地址        下一块 header
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;kmalloc&lt;/code&gt; 返回的指针指向数据区起始，而不是 header。&lt;code&gt;kfree&lt;/code&gt; 时把指针往前偏移 &lt;code&gt;sizeof(block_t)&lt;/code&gt;，找回 header，再改 &lt;code&gt;is_free = 1&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;堆在哪里&#34;&gt;堆在哪里&lt;/h2&gt;
&lt;p&gt;堆从虚拟地址 &lt;code&gt;0x30000&lt;/code&gt; 开始，链表头指针存在 &lt;code&gt;0x29000&lt;/code&gt;（一个固定位置，方便任何地方都能找到它）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define HEAP_START      0x30000ULL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define HEAP_HEAD_ADDR  0x29000ULL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define heap_head  (*(block_t **)HEAP_HEAD_ADDR)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;初始化时预先映射 4 页（16KB）作为起始堆空间，不够了再动态扩展。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
