LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1905|回复: 10

关于Kernel 内存管理的小问题

[复制链接]
发表于 2007-11-11 00:07:59 | 显示全部楼层 |阅读模式
1。 在看<Kernel Virtual Memory Management>的时候,看到内核把0-1GB的物理内存 Zone_Normal 都映射为内核的地址,而用户可用的是1-3gb的物理地址(zone_highmem).

那么,对于实际物理内存<1GB的机器,内核/用户内存怎么区隔呢?

2。看arch/i386/kernel/setup.c,Linux先通过820E中断,根据BIOS里,得到实际物理内存的大小。然后分析命令行里MEM的值。如果MEM的值<实际内存,那么是不是系统就以MEM的值作为可用内存大小? 如果MEM>实际内存呢?

谢谢
发表于 2007-11-12 09:51:03 | 显示全部楼层
小于1G,内核和用户共享。
回复 支持 反对

使用道具 举报

发表于 2007-11-15 00:45:21 | 显示全部楼层
内存大小指的是page frame的大小,与地址空间没有直接联系,内核和用户进程都有可能映射到HighMem Zone或是Normal Zone。内核分配内存的方式主要有:vmalloc(从slab分配page,物理地址可能不连续), kmalloc(从cache中分配,返回虚拟地址), alloc_pages(从zoned buddy system中直接分配物理地址连续的pages)。这三个最终都会调用__alloc_pages去buddy system中分配物理内存。当物理内存小于1G(896M)时,HighMem Zone没有物理内存,所以buddy system直接在其他zone分了内存给他,当可用物理内存达到一定限度时,内核试图释放一部分缓存或是把部分用户进程占用的物理内存交换到二级存储介质(硬盘)上去,这是一个十分耗时的操作。
当物理内存大于1G时,内核有更多的物理内存可用,需要交换到二级存储介质(硬盘)的次数减少,系统总体性能上升。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-11-15 02:12:52 | 显示全部楼层
谢谢楼上2位

我的机器,用的是2.6.18 vanilla 内核,刚好只有1G内存

也就是说,应该有2^30 bytes, 一个4K页面是2^12 Bytes, 所以应该有 2^18 = 262144 frames,

我写了一个module, 把内核的数据打印到 /proc

int contig_page_data_read(char* buf, char ** start, off_t off,int count,int *eof,void *data)
{
  ....
  len += sprintf(buf + len, "start_pfn=%ld, present pages=%ld,spanned pages=%ld,node id=%d\n", contig_page_data.node_start_pfn, contig_page_data.node_present_pages, contig_page_data.node_spanned_pages, contig_page_data.node_id);
....
}

奇怪的是
cat /proc/peek/contig_page_data
输出
start_pfn=0, present pages=261935,spanned pages=261935,node id=0

也就是说,系统才用了261935个frame, (mem_map的大小就依据这个来分配的),262144-261935 = 209个frame去那里了呢?

另外,如果只有1G物理内存的话,应该ZONE HIGHMEM里没有页面吧,可是我打印了每个ZONE 的信息:

***** ZONE 0 (ZONE_DMA) *****
pages_min=17, pages_low=21, pages_high=25
zone_start_pfn=0,spanned pages=4096, present_pages=4096

***** ZONE 1 (ZONE_DMA32) *****
H 0, N 0, D32 1, D 0
pages_min=0, pages_low=0, pages_high=0
zone_start_pfn=0,spanned pages=0, present_pages=0

***** ZONE 2 (ZONE_NORMAL) *****
H 0, N 1, D32 0, D 0
pages_min=939, pages_low=1173, pages_high=1408
zone_start_pfn=4096,spanned pages=225280, present_pages=225280

***** ZONE 3 (ZONE_HIGHMEM) *****
H 1, N 0, D32 0, D 0
pages_min=32, pages_low=65, pages_high=99
zone_start_pfn=229376,spanned pages=32559, present_pages=32559


显然 ZONE HIGHMEM也有页面,为什么呢?
回复 支持 反对

使用道具 举报

发表于 2007-11-15 22:48:26 | 显示全部楼层
HighMem Zone是包含896MB以上page frame,所以1G物理内存HighMem Zone有128M内存是正常的。
mem_map的page frame比预期少可能是由于内核bootup时占用了大约1M物理内存,我不是很清楚这块内存在不在mem_map array里,你可以到书上查一查那些page frame可能没有包含到mem_map中。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-11-16 00:25:17 | 显示全部楼层
恩,我又研究了一下
ZONE_DMA 没有问题,是从[0,4096), 16MB
ZONE_NORMAL也是对的,16MB 到 896MB,占用880MB,
这时, 从896-1024还有128MB, 如果没有开启CONFIG_HIGHMEM的话,这128MB是KERNEL保留的, 这样理解的话,ZONE_HIGHMEM正好应该是0, 不知道这个理解对不对?


可是,我的内核在编译的时候打开了CONFIG_HIGHMEM。这样,我的 zone_highmem就能看到 (128M-836K) 内存了。为什么少了836K(最顶端的209个frames),我得再看看代码。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-11-16 03:25:51 | 显示全部楼层
读了程序,为什么少了836K了

ZONE HIGHMEM 的区域是 (highstart_pfn, highend_pfn),  
highstart_pfn = min(max_low_pfn, max_pfn)
显然,对于1G物理内存, max_low_pfn < max_pfn
所以HIGHMEM的开始就是ZONE NORMAL的结束点,这一点和书上所说一致

而highend_pfn = max_pfn,
而max_pfn由setup_arch() -> setup_memory() -> find_max_pfn()找到,

994 void __init find_max_pfn(void)
995 {
996         int i;
997
998         max_pfn = 0;
999        ...
1004
1005         for (i = 0; i < e820.nr_map; i++) {
1006                 unsigned long start, end;
1007                 /* RAM? */
1008                 if (e820.map.type != E820_RAM)
1009                         continue;
1010                 start = PFN_UP(e820.map.addr);
1011                 end = PFN_DOWN(e820.map.addr + e820.map.size);
1012                 if (start >= end)
1013                         continue;
1014                 if (end > max_pfn)
1015                         max_pfn = end;
1016                 memory_present(0, start, end);
1017         }
1018 }

显然,max_pfn 是e820.map里面类型为E820_RAM的最大地址
在我的机器上,dmesg里有如下E820 MAP:

BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
BIOS-e820: 000000000009fc00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000e6000 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 000000003ff2fc00 (usable)
BIOS-e820: 000000003ff2fc00 - 000000003ff30000 (ACPI NVS)
BIOS-e820: 000000003ff30000 - 000000003ff40000 (ACPI data)
BIOS-e820: 000000003ff40000 - 000000003fff0000 (ACPI NVS)
BIOS-e820: 000000003fff0000 - 0000000040000000 (reserved)
BIOS-e820: 00000000fecf0000 - 00000000fecf1000 (reserved)
BIOS-e820: 00000000fed20000 - 00000000feda0000 (reserved)
127MB HIGHMEM available.
896MB LOWMEM available.

显然,类型为RAM,也就是usable的最大地址是000000003ff2fc00 , 按4K页取整为 3FF2F000, 0x3ff2f00/4K = 261935 页 = 1047740 K !

而1G= 1048596 KB,  1048596-  1047740  恰好就是丢失的 836K
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-11-16 03:27:52 | 显示全部楼层
至于为什么E820返回的可用RAM地址空间是这样,我就不知道了
回复 支持 反对

使用道具 举报

发表于 2007-11-16 21:17:25 | 显示全部楼层
可能其他固件占用了部分内存,你可以上网搜一搜有没有其他人遇到过相似问题,或是到linux相关论坛问问。本人才疏学浅,答不了这个问题。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-11-16 23:06:33 | 显示全部楼层
Post by feiliang1983;1783444
可能其他固件占用了部分内存,你可以上网搜一搜有没有其他人遇到过相似问题,或是到linux相关论坛问问。本人才疏学浅,答不了这个问题。


呵呵,过谦了
这个问题我就先放一边,接着看其他部分了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表