在本课中,内存也相关源码路径为:
kernel/kallo.c
// Physical memory allocator, for user processes,
// kernel stacks, page-table pages,
// and pipe buffers. Allocates whole 4096-byte pages.
#include "types.h"
#include "param.h"
#include "memlayout.h"
#include "spinlock.h"
#include "riscv.h"
#include "defs.h"
void freerange(void *pa_start, void *pa_end);
extern char end[]; // first address after kernel.
// defined by kernel.ld.
struct run {
struct run *next;
};
struct {
struct spinlock lock;
struct run *freelist;
} kmem;
void
kinit()
{
initlock(&kmem.lock, "kmem");
freerange(end, (void*)PHYSTOP);
}
void
freerange(void *pa_start, void *pa_end)
{
char *p;
p = (char*)PGROUNDUP((uint64)pa_start);
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
kfree(p);
}
// Free the page of physical memory pointed at by pa,
// which normally should have been returned by a
// call to kalloc(). (The exception is when
// initializing the allocator; see kinit above.)
void
kfree(void *pa)
{
struct run *r;
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run*)pa;
acquire(&kmem.lock);
r->next = kmem.freelist;
kmem.freelist = r;
release(&kmem.lock);
}
uint64
kfreemem(void)
{
struct run *r;
uint64 count = 0;
acquire(&kmem.lock);
r = kmem.freelist;
while(r) {
r = r->next;
count++;
}
release(&kmem.lock);
return count * PGSIZE;
}
// Allocate one 4096-byte page of physical memory.
// Returns a pointer that the kernel can use.
// Returns 0 if the memory cannot be allocated.
void *
kalloc(void)
{
struct run *r;
acquire(&kmem.lock);
r = kmem.freelist;
if(r)
kmem.freelist = r->next;
release(&kmem.lock);
if(r)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}
如何在一个物理内存上,创建不通的地址空间?
如上所述:
最常见的就是分配页,页表(pagetables) – 需要硬件支持或者通过内存管理单元实现(MMU – Memory Management Unit)

上图展示了如下步骤:
内存地址对应关系 这张表单也保存在内存中,所以CPU中需要一些寄存器(SATP)来存放表单在物理内存中的地址,用来告诉 MMU 去哪里找这份表单页表存的是物理地址
通过虚拟地址找到对应的表单和偏移。)
(多级页表,某种意义上也代表着会读多次内存)




在操作系统,对于物理内存来说,每一个地址间隔所代表的的物理存储单位为 1B(一个字节,这里先不要考虑钻进64位本身占多少的错误思维(我自己之前就是));
所以一个64位操作系统,不考虑其他因素,CPU的可寻址大小最大为 2^64 Byte(32位是4G,下面的例子拿32位距离比较好理解)
将物理内存按照块或页分配,概念上理解成每 4KB 一页。即 2^12,即32位地址中,低的那12位可以用来表示对 page table 某页的 Offset, 即偏移。这里存在如下计算:
32 / 8 = 4 B 的空间,为了方便所以使用了 4B 作为页表项,这样一个页表就可以有 4KB / 4B = 1K 页表项(单位是页标项)2^64 / 2^12 = 2^52 页4GB / 4KB * 4B == 4MB , 总内存就是 4G + 4MB;而如果是二级页表:4MB / 4KB == 1K 页 --> 1K页 * 4B == 1KB, 占用 4G + 1KB相关笔记:顶级页表最多只能有一个页面。(这是规定)
一个页面可以存放1K个页表项4KB/4B = 1K。
所以顶级页表虽然只有一个页面但是可以存放1K个页表项,其中每一个页表项对应的是下一级的1K个页表项。所以可以存放的最大空间是1K* 1K *4KB = 4GB内存。