/***************************************************************************************************
*文件功能:验证内存分配的地方
*编译环境:SUSELinux
*编译结果:成功
*实验结果:与理论不相符,可能因为是虚拟机的原因。
*实 验 者:张永辉 2012年9月13日
理论:
linux提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件支持)的处理器而言,
Linux 提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。
LINUX进程的 4GB 内存空间被人为的分为两个部分
4G = 0X00000000-0X3FFFFFFF
0X40000000-0X7FFFFFFF
0X80000000-0XBFFFFFFF
0XC0000000-0XFFFFFFFF
用户空间
0--3GB是用户空间 即0x00000000---0xBFFFFFFF(PAGE_OFFSET,在 0x86 中它等于 0xC0000000)
内核空间
1G是内核空间按 即0XC0000000---0XFFFFFFFF
3G---vmalloc_start 这段地址是物理内存映射区域(该区域中包含了内核镜像、物理页框表 mem_map 等等),
比如我们使用的 VMware 虚拟系统内存是 160M,那么 3G~3G+160M 这片内存就应该映射物理内存。
对于160M的系统而言,vmalloc_start 位置应在 3G+160M 附近(在物理内存映射区与vmalloc_start 期间还存在一个 8M 的 gap 来防止跃界),
vmalloc_start---0XFFFFFFFF 是 vmalloc 区域
vmalloc_end 位置接近 4G(最后位置系统会保留一片 128k 大小的区域用于专用页面映射)
内存的操作:
kmalloc 和 get_free_page //include\asm-i386\io.h
他们申请的内存位于3G---vmalloc_start,物理上是连续的,与真实的物理地址只有一个固定的偏移.
转换关系如下:
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
extern inline unsigned long virt_to_phys(volatile void * address) //虚拟地址减去3G(PAGE_OFFSET=0XC000000)得到 物理地址
{ return __pa(address); }
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
extern inline void * phys_to_virt(unsigned long address)
{
return __va(address); //内核物理地址转化为虚拟地址
}
vmalloc
申请的内存则位于 vmalloc_start~vmalloc_end 之间,与物理地址没有简单的转换关系,在逻辑上也是连续的,但在物理不要求连续。
实验结果:
连续进行三次 insmod rmmod 操作,三个函数申请得到的内存地址如下
__get_free_page() [addr应该 = 0xc0000000--0xc0000000+16M]
pagemem addr=0X496e5000
pagemem addr=0Xcd7a1000
pagemem addr=0X9e005000
kmalloc() [addr应该 = 0xc0000000--0xc0000000+16M]
kmallocmem addr=0X26530ac0
kmallocmem addr=0Xbe7e61c0
kmallocmem addr=0X4775a640
vmalloc() [addr应该 = 0xc0000000+16M--0XFFFFFFFF-128K]
vmallocmem addr=0X222c000
vmallocmem addr=0X2246000
vmallocmem addr=0X2260000
事实上不是这样的,求解为什么?
***************************************************************************************************/
/***************************************************************************************************
* mem.c :查看内存分配地址
编译环境:SUSELinux
编译结果:成功,见注释
实 验 者:张永辉 2012年9月13日
***************************************************************************************************/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for printk:KERN_ALERT */
#include <linux/init.h>
//#include <linux/slab.h>
#include <linux/vmalloc.h> //kmalloc() vmalloc() 's headfile
MODULE_LICENSE("Dual BSD/GPL");
unsigned char *pagemem;
unsigned char *kmallocmem;
unsigned char *vmallocmem;
static int mem_init(void)
{
pagemem = (unsigned char*)__get_free_page(0);
kmallocmem = (unsigned char*)kmalloc(100, 0);
vmallocmem = (unsigned char*)vmalloc(100000);
printk(KERN_EMERG "pagemem addr=0X%x \n" , pagemem);
printk(KERN_EMERG "kmallocmem addr=0X%x \n" , kmallocmem);
printk(KERN_EMERG "vmallocmem addr=0X%x \n" , vmallocmem);
printk(KERN_EMERG "Hello world\n");
return 0;
}
static void mem_exit(void)
{
printk(KERN_EMERG "Goodbye world\n");
}
module_init(mem_init);
module_exit(mem_exit);