内存管理-page初始化,分配与回收
来源:互联网 发布:网络传播与策划 刘芸 编辑:程序博客网 时间:2024/05/10 19:26
内存管理-page初始化,分配与回收
物理页面不一定就是物理内存页面,也可能是盘上物理页面
内核把叶作为内存管理的基本单位,物理内存和虚拟内存都分成大小相等的页(4K)
在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操作系统只将当前正在使用的程序和数据块保留在内存中,而将内存容纳不了的信息保留在磁盘上。必要时,操作系统负责在磁盘和内存之间交换(怎么确定不用)程序和数据块
mm/init.c的作用:
内存布局:
内核被装载在2M(_text)开始处,结束_etext,紧接着是内核数据至_end
第0页用于保存BIOS检测的硬件信息
0x000a0000 to 0x000fffff保存BIOS例程,即640K到1M
ffff0000 BIOS rom 的首地址
machine_specific_memory_setup( ):内存状况表
检查
----------------------------------------------------------------------------物理
page_size
page_offset:0xC0000000
PMD_SHIFT 22
内存管理单元(MMU,管理内存把虚拟地址转换为线性地址的硬件)以页为单位进行处理
内核用struct page---include/linux/mm.h结构的代表每个物理页,即每个物理页一个(一段连续地址)
全局指针mem_map指向page数组,在数组里分成三个区
建立块(在到分区)
pglist_date:include/linux/mmzone.h
typedef struct pglist_data {
zone_t node_zones[MAX_NR_ZONES];指向三个zone分区
zonelist_t node_zonelists[GFP_ZONEMASK+1];分配策略
int nr_zones; // Number of zones in the node
struct page *node_mem_map;指向具体page节点
unsigned long *valid_addr_bitmap;
struct bootmem_data *bdata;
unsigned long node_start_paddr;
unsigned long node_start_mapnr;
unsigned long node_size;
int node_id;
struct pglist_data *node_next;
} pg_data_t;
分区:内核为了管理叶而进行的一种逻辑分区struct zone(linux/mmzone.h)
由于外围器件很多,速度多不同,基本上每个空间都有分区,因为同一分区内访问速度相同,即介质均匀,所以在zone之上有个节点即pglist,每个pglist再有分区
zone_DMA(<16)DMA只能访问内存的前16M
zone_NORMAL(16-896)
zone_HIGHMEM(>896)
typedef struct zone_struct {
spinlock_t lock;
unsigned long offset;该区在全局页表中的起始页号
unsigned long free_pages;
unsigned long pages_min, pages_low, pages_high;
int need_balance;
free_area_t free_area[MAX_ORDER];一组空闲区间队列,管理散的物理页面成块,保持伙伴系统的连续长度页面块 空闲,活跃
struct pglist_data *zone_pgdat;
struct page *zone_mem_map;
unsigned long zone_start_paddr;
unsigned long zone_start_mapnr;
char *name;
unsigned long size;
} zone_t;
typedef struct zonelist_struct {
zone_t * zones [MAX_NR_ZONES+1]; // 指针数组,各个元素指向对应管理区,零终止,分配页面时尝试不同的管理区
} zonelist_t;
物理内存管理器负责管理系统中宝贵的物理内存资源。利用位图可记录内存单元的使用情况,利用链表则可以分别记录已分配的内存单元和空闲的内存单元
struct free_area_struct {
struct page *next; 物理页块结构page的哈希头中指针
struct page *prev;
unsigned int * map; 分配情况位图
}free_area_t;构成伙伴系统,管理的最小内存块的大小是1页(4K),最大内存块的大小是512页(2M)或2048页)8M
-----------------------------------------------------这些都是物理空间管理
The Zoned Page Frame Allocator
请求调页:
malloc分配虚存结构vma_area_struct
空闲连入struct zone_struct-> free_area
获得页:mm/page_alloc.c get_free_pages(特殊要求,指数)调用alloc_pages()检查是否超出最大调用_alloc_pages()进行具体分配,使用计数加1,page_address()返回page->virture。
交换:swap_info_struct include/linux/swap.h
用户空间页面:普通段,mmap映射,共享内存
页回收:free_pages()
内核交换守护进程kswapd:当物理内存缺乏的时候,尝试释放某些物理页。保证系统有足够的空闲页,使内存管理系统能有效地运行
?tlb和cache基址内核自动实现
内核缓冲区管理器:
什么时使用cache:看具体代码谁调用
cache:一个cache管理一组大小固定的内存块,kmem_cache_s描述,系统中的所有cache结构通过其中的指针(c_nextp)连成一个环型链表。cache中的内存块来自一到多个slab
cache数据结构中有三个指针,,完全活动的slab(所有对象均在使用)在前、
部分活动的slab居中
空闲slab排在最后
高速缓存与slab的关系:
分配一个slab到cache:
释放一个slab从cache:
分配一个slab对象:
释放一个slab对象:
slab:一个slab是来自物理内存管理器的一到多个物理页。每个slab都用一个kmem_slab_s数据结构描述。属于同一个cache的所有slab用其中的s_nextp和s_prevp连成一个双向链表
并不丢弃已分配的对象,提高效率,应该是保存在cache的不同状态队列中
slab用于减少伙伴分配算法的调用,进程创建的很频繁,但所占空间大致相同
小区间的分配,减少碎片
slab管理的对象:kmem_bufctl_s
第14章进程地址空间
每一个进程都有自己的虚拟地址空间,所有进程共享内核空间(c0000000-ffffffff)
define page_offset 0xc0000000
内核编辑阶段,在arch/i386/kernel/head.S startup_32( )创建了一个临时全局页表,存放在变量swapper_pg_dir,位置在内核数据_end后面第一个页
最终页表转换:arch/i386/mm---pagetable_init( )注意针对实际不同大小物理内存的处理。
对于系统空间而言:给定一个虚拟地址X,其物理地址便为X+page_offset
内核运行在物理寻址模式,不需要页表
每个内存有进程要遵守的属性,可读可写可执行。访问不在有效范围内、或以不正确的方式访问,内核会结束该进程,返回段错误。
内存描述符:mm_struct—linux/sched.h该结构描述了一个进程的地址空间的所有信息,包括其页目录、内存区域结构的链表和树、LDT(segments)、以及各种数据在其虚拟地址空间中的起止位置、以及一些统计信息
创建和删除进程的地址空间:
分配内存描述符:fork()调用copy_mm()复制父进程的current->mm内存描述符
子进程通过fork.c中allocte_mm()宏从mm_cachep slab缓存中分配得到
如果想父子进程共享内存,调用clone()时社标志CLONE_VM,即线程,内核不再调用allocte_mm().仅仅做copy_mm().
销毁内存描述符:内核调用exit_mm()函数
每一个进程都拥有自己的页表(页目录+页表)。内核创建,处理页表项
一级页表浪费存储空间 ,linux采用三级页表
每个虚拟地址都为四个字段,三个页编号和一个偏移量
第一级页表的基地址存好CR3,注意进程切换时它的值要变
asm volatile(“mov %0,%%cr3”::”r”(_pa(next->pgd)))
include/asm-i386/pgtable-2level.h
宏PGD_SHIFT(22)表示线性地址中一级页表的起始偏移,即22-32高十位,
即PGD得指针数为2^10即1024个(每个指针4,PGD表4K),pgtable.h中PGDIR_SIZE代表PGD中每项指向2^22个空间
用第一级页编号PGD查第一级页表(此进程第一级页表其它项为0),得到第二级页表的基地址;
用第二级页编号PMD查第二级页表,得到第三级页表的基地址;
用第三级页编号查第三级页表PTE,得到物理页的基地址;
页表项pte_t的高20位看做物理页面的序号,低12位用于状态信息和访问权限,但是并不是定义在PTE中,另定义pgprot_t(include/asm-i386/page.h)具体定义pgtable.h
页表项的获得pgtable-2level.h,
present: 1==pte_present()相应页已被装入主存Accessed:交换时使用Dirty:Read/Write:User/Supervisor:PCD and PWT:Page Size :Global
将物理页的基地址加上偏移量,就得到了该虚拟地址对应的物理地址。
之后利用地址的方式:
映射过程由MMU完成
include/asm/pgtable.h
在Intel处理器的pgtable.h文件中,定义一组宏(内核能处理特定进程的页表。这样,内核就不需要知道页表条目的具体结构和组织情况)。understanding2.5
相应表项为0,那么pte_none()返回1。
pte_clear()清一个表项,set_pte()将表项设定为一个特定值
pte_user()读user状态 ptr_wrprotect()设读写状态
还有页操作和页分配函数
每个进程都有局部段描述表LDT和任务状态段TSS,两个表的起始地址都作为全局描述表GDT的一项。GDT最大能容忍8192项。内核基本上用的都是GDT.arch/i386/kernel/heads.s
(GDT的每位解释P41-情景分析)
CS,DS的定义include/asm-i386/segment.h 映像processor/h define start_thread
转换过程:缺页中断,产生异常,异常处理函数do_page_fault()arch/i386/mm/fault.c
32位地址意味着4G的虚拟地址空间
用户空间--虚拟内存区域:vm_area_struct(linux/mm.h)指定虚拟地址空间内连续的一个内存范围对同一块区域的处理有着相同的规则。我们需要用虚存空间的哪些部分。
实际使用的内存区域:cat /proc/任一项/maps
虚拟内存管理:
操作内存区域:判断进程地址空间内存是否满足某些条件
Find_vma()查找一个addr所在的区域。给定虚拟地址,找到对应的结构
创建虚拟结构体后insert_vm_struct()将其插入mm_struct的队列或AVL树中
Mmap()通过系统调用获得do_mmap()的功能(文件映射到内存,按指针方式便可操作)
do_mmap()创建一个新的线性空间,建立映射。include/linux/mm.h如果创建的空间与原来的空间相连则合成一个
Munmap()从特定的地址空间中删除指定的地址空间
请求调页:
写时复制:
typedef struct page {
struct list_head list; /* ->mapping has some page lists. */
struct address_space *mapping; /* The inode (or ...) we belong to. */
unsigned long index; /* Our offset within mapping. */
struct page *next_hash; /* Next page sharing our hash bucket in
the pagecache hash table. */
atomic_t count; /* Usage count, see below. */
unsigned long flags; /* atomic flags, some possibly
updated asynchronously */
struct list_head lru; /* Pageout list, eg. active_list;
protected by pagemap_lru_lock !! */
wait_queue_head_t wait; /* Page locked? Stand in line... */
struct page **pprev_hash; /* Complement to *next_hash. */
struct buffer_head * buffers; /* Buffer maps us to a disk block. */
void *virtual; /* Kernel virtual address (NULL if
not kmapped, ie. highmem) */
struct zone_struct *zone; /* Memory zone we are in. */
} mem_map_t;
struct kmem_cache_s {
/* 1) each alloc & free */
/* full, partial first, then free链表的双向指针 */
struct list_head slabs_full;同一个cache中不同状态的slab各自组成一个链表
struct list_head slabs_partial;
struct list_head slabs_free;
unsigned int objsize; // Size of the objects included in the cache
unsigned int flags; /* constant flags */
unsigned int num; /* num of objs per slab */
spinlock_t spinlock;
#ifdef CONFIG_SMP
unsigned int batchcount; Chunk size for local cache refill or emptying
#endif
/* 2) slab additions /removals */
/* order of pgs per slab (2^n) */
unsigned int gfporder;
/* force GFP flags, e.g. GFP_DMA */
unsigned int gfpflags;//分配页面时传递给伙伴函数的参数
size_t colour; /* cache colouring range */
unsigned int colour_off; /* colour offset */
unsigned int colour_next; /* cache colouring */
kmem_cache_t *slabp_cache; //通用slab_cache的指针
unsigned int growing;
unsigned int dflags; /* dynamic flags */
/* constructor func */
void (*ctor)(void *, kmem_cache_t *, unsigned long);
/* de-constructor func */
void (*dtor)(void *, kmem_cache_t *, unsigned long);
unsigned long failures;
/* 3) cache creation/removal */
char name[CACHE_NAMELEN]; //cache的name
struct list_head next; //cache的双向链表指针
#ifdef CONFIG_SMP
/* 4) per-cpu data */
cpucache_t *cpudata[NR_CPUS];
#endif
#if STATS
unsigned long num_active;
unsigned long num_allocations;
unsigned long high_mark;
unsigned long grown;
unsigned long reaped;
unsigned long errors;
#ifdef CONFIG_SMP
atomic_t allochit;
atomic_t allocmiss;
atomic_t freehit;
atomic_t freemiss;
#endif
#endif
};
typedef struct slab_s {
struct list_head list;//指向上面结构体前三个变量的指针
unsigned long colouroff;//slab中第一个对象的偏移
void *s_mem; //第一个分配对象的地址
unsigned int inuse; /* num of objs active in slab */
kmem_bufctl_t free; //Index of next free object in the slab, or BUFCTL_END if there are no free objects left
} slab_t;
对象:
typedef unsigned int kmem_bufctl_t
#define slab_bufctl(slabp) ((kmem_bufctl_t *)(((slab_t*)slabp)+1))
- 内存管理-page初始化,分配与回收
- 可变分区存储管理的内存分配与回收
- 内存分配与初始化
- 内存分配与回收策略
- 内存分配与回收策略
- java内存分配与回收
- JVM内存分配与回收
- JVM内存回收与分配
- 内存分配与回收策略
- 垃圾回收与内存分配
- 内存分配与回收策略
- 内存分配与回收策略
- 内存分配与回收策略
- 内存分配与回收策略
- Java内存回收与分配
- linux内存分配与回收
- 内存分配与回收策略
- 内存分配与回收策略
- Backtrack 4: Crack WPA2
- 如何阅读linux内核源码
- zoj 1027 Human Gene Functions
- Web dynpro的SELECT-OPTIONS做成方法
- 构建form,保护隐私数据传递给本身,并且通过pre_init改变theme
- 内存管理-page初始化,分配与回收
- Larbin learning (1)——How to compile and use larbin
- 修改host访问Google Chrome官方扩展页
- 两道面试题
- 存货收发存应用实例
- #include的用法
- wally同盟社特别版(免安装密码)
- JAR 文件包
- 数字图像缩放算法