操作系统就用一张大表惩处内存?
发布日期:2022-05-15 16:23 点击次数:82
今天咱们不聊具体内存惩处的算法,咱们就来望望,操作系统用什么样的一张表,达到了惩处内存的后果。
咱们以 Linux 0.11 源码为例,发现参加内核的 main 函数后不久,有这样一坨代码。
void main(void) { ... memory_end = (1<<20) + (EXT_MEM_K<<10); memory_end &= 0xfffff000; if (memory_end > 16*1024*1024) memory_end = 16*1024*1024; if (memory_end > 12*1024*1024) buffer_memory_end = 4*1024*1024; else if (memory_end > 6*1024*1024) buffer_memory_end = 2*1024*1024; else buffer_memory_end = 1*1024*1024; main_memory_start = buffer_memory_end; mem_init(main_memory_start,memory_end); ... }
除了临了一转外,前边的那一大坨的作用很肤浅。
其实就仅仅针对不同的内存大小,树立不同的鸿沟值驱散,为了认知它,咱们完全没必要探求这样周详,就假定总内存一共就 8M 大小吧。
那么若是内存为 8M 大小,memory_end 等于
8 * 1024 * 1024
也就只会走倒数第二个分支,那么 buffer_memory_end 就为
2 * 1024 * 1024
那么 main_memory_start 也为
2 * 1024 * 1024
你仔细望望代码逻辑,看是不是这样?
虽然,你不肯意细想也没联系,上述代码实施后,等于如下后果费力。
你看,其实等于定了三个箭头所指向的地址的三个鸿沟变量。具体主内存区是如何惩处和分拨的,要看 mem_init 里做了什么。
void main(void) { ... mem_init(main_memory_start, memory_end); ... }
而缓冲区是如何惩处和分拨的,就要看再背面的 buffer_init 里干了什么。
void main(void) { ... buffer_init(buffer_memory_end); ... }
不外咱们今天只看,主内存是如何惩处的,很肤浅,放平缓。
参加 mem_init 函数。
#define LOW_MEM 0x100000 #define PAGING_MEMORY (15*1024*1024) #define PAGING_PAGES (PAGING_MEMORY>>12) #define MAP_NR(addr) (((addr)-LOW_MEM)>>12) #define USED 100 static long HIGH_MEMORY = 0; static unsigned char mem_map[PAGING_PAGES] = { 0, }; // start_mem = 2 * 1024 * 1024 // end_mem = 8 * 1024 * 1024 void mem_init(long start_mem, long end_mem) { int i; HIGH_MEMORY = end_mem; for (i=0 ; i<PAGING_PAGES ; i++) mem_map[i] = USED; i = MAP_NR(start_mem); end_mem -= start_mem; end_mem >>= 12; while (end_mem-->0) mem_map[i++]=0; }
发现也没几行,并且并莫得更深的标准调用,看来是个好耻辱的标准。
仔细一看这个标准,其实折腾来折腾去,等于给一个 mem_map 数组的各个位置上赋了值,并且败露一道赋值为 USED 也等于 100,然后对其中一部分又赋值为了 0。
赋值为 100 的部分等于 USED,也就暗意内存被占用,若是再具体说是占用了 100 次,这个之后再说。剩下赋值为 0 的部分就暗意未被使用,也即使用次数为零。
是不是很肤浅?等于准备了一个表,记载了哪些内存被占用了,哪些内存没被占用。这等于所谓的“惩处”,并莫得那么妙趣横生。
那接下来当然有两个问题,每个元素暗意占用和未占用,这个暗意的鸿沟是多大?开动化时哪些场地是占用的,哪些场地又是未占用的?
依然一张图就看赫然了,咱们仍然假定内存所有这个词唯有 8M。
不错看出,开动化完成后,其实等于 mem_map 这个数组的每个元素都代表一个 4K 内存是否沉着(准确说是使用次数)。
4K 内存频繁叫做 1 页内存,而这种惩处样式叫分页惩处,等于把内存分红一页一页(4K)的单元去惩处。
1M 以下的内存这个数组干脆莫得记载,这里的内存是无需惩处的,概况换个说法是无权惩处的,也等于莫得权力苦求和开释,因为这个区域是内核代码所在的场地,不成被“浑浊”。
1M 到 2M 这个区间是缓冲区,2M 是缓冲区的结尾,缓冲区的起始在那边之后再说,这些场地不是主内存区域,因此径直标识为 USED,产生的后果等于无法再被分拨了。
2M 以上的空间是主内存区域,而主内存现在莫得任何圭臬苦求,是以开动化时十足都是零,改日等着期骗圭臬去苦求和开释这里的内存资源。
那期骗圭臬如何苦求内存呢?咱们本讲不张开,不外咱们肤浅有计划一下,望望苦求内存的流程中,是如何使用 mem_map 这个结构的。
在 memory.c 文献中有个函数 get_free_page(),用于在主内存区中苦求一页沉着内存页,并复返物理内存页的肇端地址。
比如咱们在 fork 子程度的时分,会调用 copy_process 函数来复制程度的结构信息,其中有一个圭臬等于要苦求一页内存,用于存放程度结构信息 task_struct。
int copy_process(...) { struct task_struct *p; ... p = (struct task_struct *) get_free_page(); ... }
咱们看 get_free_page 的具体杀青,是内联汇编代码,看不懂没联系,精通它内部就有 mem_map 结构的使用。
unsigned long get_free_page(void) { register unsigned long __res asm("ax"); __asm__( "std ; repne ; scasb\n\t" "jne 1f\n\t" "movb $1,1(%