linux内存管理子系统 笔记

linux内存管理子系统 笔记
linux内存管理子系统 笔记

4-4 linux内存管理子系统

4-4-1 linux内存管理(参考课件)

物理地址:cpu地址总线上寻址物理内存的地址信号,是地址变换的最终结果

逻辑地址:程序代码经过编译后,出现在汇编程序中的地址(程序设计时使用的地址)

线性地址:又名虚拟地址,32位cpu架构下4G地址空间

CPU要将一个逻辑地址转换为物理地址,需要两步:

1、首先CPU利用段式内存管理单元,将逻辑地址转换成线性地址;

2、再利用页式内存管理单元,把线性地址最终转换为物理地址

相关公式:

逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)(通用的)

16位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)

线性地址=段寄存器的值×16+逻辑地址的偏移部分

物理地址=线性地址(没有页式管理)

32位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)

线性地址=段寄存器的值+逻辑地址的偏移部分

物理地址<——>线性地址(mapping转换)

ARM32位:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)

逻辑地址=段内偏移量(段基地址为0)

线性地址=逻辑地址=段内偏移量(32位不用乘以32)

物理地址<——>线性地址(mapping转换)

************************!!以下都是x86模式下!!*********************************

一、段式管理

1.1、16位CPU:(没有页式管理)

1.1.1、段式管理的由来:

16位CPU内部有20位地址总线,可寻址2的20次方即1M的内存空间,但16位CPU 只有16位的寄存器,因此只能访问2的16次方即64K。因此就采用了内存分段的管理模式,在CPU内部加入了段寄存器,这样1M被分成若干个逻辑段,每个逻辑段的要求如下:

1、逻辑段的起始地址(段地址)必须是16的整数倍,即最后4个二进制位须全是0 (因此不必保存)。

2、逻辑段的最大容量为64K。

1.1.2、物理地址的形成方式:

段地址:将段寄存器中的数值左移4位补4个0(乘以16),得到实际的段地址。

段偏移:在段偏移寄存器中。

1)逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)

2)由逻辑地址得到物理地址的公式为:(因为没有页式管理,所以这一步就得到了物理地址)物理地址PA=段寄存器的值×16+逻辑地址的偏移部分(注意!!)(段与段可能会重叠)

按段式管理能访问2的32次方共4GB 的空间(2的16次方个段,每个段可以为2的16次方byte的大小),但是只有20位地址总线,因此只能访问1M的内存。

1.2、32位CPU:

1)实模式:

与16位时是一样的

段寄存器的值×16就是段地址

2)保护模式:

段寄存器的值是一个选择器,间接指出一个32位的段地址

段基地址长达32位,每个段的最大容量可达4G,段寄存器的值是段地址的“选择器”(segment selector),用该“选择器”从内存(segment descriptor)中得到一个32位的段地址,存储单元的线性地址就是段地址加上段内偏移量,这与32位CPU的物理地址的计算方式完全不同。

!!!线性地址=段基地址+段内偏移量/逻辑地址(段选择器指向的内存中存储的基地址+段偏移寄存器)!!! 这里不用乘以16或者32,因为段基址寄存器可以完全存下段地址。

32位CPU得到线性地址后,再经过页式管理就能得到物理地址

二、页式管理

2.1页:线性地址被分为固定长度的组,称为页。例如32位的机器,每页4KB,可划为2的20次方个页(划分虚拟单元),32位机器的线性地址空间为4G。

2.2物理页:也称为页框、页桢;分页单元把所有的物理内存也划分为固定长度的管理单位(划

分实在的单元),它的长度一般与线性地址页是相同的。

二者的区别:页划分的是线性地址,物理页划分的是实际的物理地址

二者的联系:1、页的长度一般相同,2、通过mapping转换,存在映射关系。

通过分页管理模型,由线性地址得到物理地址

1、分页单元中,页目录的地址存放在CPU的cr3寄存器中,是进行地址转换的开始点。

2、每个进程,都有其独立的虚拟地址空间,运行一个进程,首先要将它的页目录地址放到cr3寄存器中,将其他进程的页目录地址保存下来。

3、每个32位的线性地址被划分为三部分:页目录索引(10位);页表索引(10位);偏移(12位)

(mapping映射关系由下图反映)

上图中页的大小为2的12次方,即4K。两级分页模型(页不算在内)

******************************!!以上都是x86模式!!*********** *******************

Linux内存管理

Linux有限度地使用了Intel的段式管理机制,而完全采用了页式管理机制。(也可以说没有采用段式管理)

所有段的基地址全部为零(那么所有段都重合,相当于只有一个段)

又因为"线性地址=段基地址+段内偏移量/逻辑地址偏移部分",

所以"线性地址=逻辑地址"。

在linux系统中,逻辑地址=线性地址=虚拟地址

物理地址<——>线性地址(mapping转换)

linux页式管理

linux2.6.29内核采用了四级页式管理架构,来兼容二级、三级管理架构的CPU。

页全局目录、页上级目录、页中间目录、页表(四级时,线性地址为64位)

4-4-2进程地址空间(参考课件)

linux操作系统采用虚拟内存管理技术,使得每个进程的地址空间都是独立的。该空间大小是3G,用户看到的都是虚拟地址,无法看到实际的物理地址。

虚拟内存管理的优点:1、保护操作系统,

2、用户程序可以使用比实际物理内存更大的地址空间。

linux将4G的虚拟地址空间划分为用户空间和内核空间。

用户空间:0~0xbfffffff(0~3G):用户进程通常情况下只能访问用户空间。

内核空间:0xc0000000~0xffffffff(3G-4G)

用户空间对应进程,所以每当进程切换,用户空间就会跟着变化。每个进程的地址空间都是独立的。每个进程的页目录、页表不一样,因此通过页式转换就可以得到不同的物理地址。例如:

同一个用户程序运行多次,产生多个进程,每个进程访问的虚拟地址(逻辑地址、线性地址)都是一样的,但是每个进程都有一套独立的页目录、页表,因此得到的实际物理地址是不同的。每个进程的页目录和页表就可以理解为进程独立的用户空间。

Fork(),execve(),malloc()等进程相关操作分配的内存,都是虚拟地址。只有当进程去访问新获取的虚拟地址时,才会由“请页机制”去分配实际的物理地址。

实际的物理内存只有当进程真的去访问新获取的虚拟地址时,才会由“请页机制”产生“缺页”异常,从而进入分配实际页框的程序。该异常是虚拟内存机制赖以生存的基本保证——它会告诉内核去为进程分配物理页,并建立对应的页表,这之后虚拟地址才实实在在地映射到了物理地址上。

动态分配——Linux内核中,动态分配内存使用函数kmalloc()

头文件:#include

原型:void *kmalloc(size_t size,int flags) ——kfree,适用于分配小于128KB的内存

功能:分配实际的物理页框,虽然返回的是虚拟地址,但已经有对应的物理页了。

参数:Flags取值为:

1、GFP_KERNEL,分配实际的内存,分配不到时睡眠。返回虚拟地址,但对应有实

际的物理单元。(16M-896M)

2、GFP_ATOMIC,用来在进程上下文之外的代码(包括中断处理)中分配内存,

从不睡眠。

3、__GFP_DMA,要求分配能够DMA的内存(物理地址在16M以下的页桢)

4、__GFP_HIGHMEM,分配的内存位于高端内存。(896M以上)

当用完这些页,需要使用下列函数之一来释放它们:

◎kfree函数

◎get_zeroed_page(unsigned int flags)——free_page

返回指向新页面的指针,并将页面清零。

◎__get_free_page(unsigned int flags)——free_page

和get_ zeroed _page类似,但不清零页面。

◎__get_free_pages(unsigned int flags,unsigned int order)——free_pages

分配若干的连续的页面,返回指向该内存区域的指针,但也不清零这段内存区域。

当用完这些页,需要使用下列函数之一来释放它们:

◎void free_page(unsigned long addr)

◎void free_pages(unsigned long addr,unsigned long order)

如果释放的页面和先前分配的页面数目不等,会导致系统错误。

4-4-3内核地址空间(参考课件)

内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。内核映射的这一套页目录、页表是固定不变的。内核空间:3G-4G。

高端内存:物理内存896M以上的内存。

1、直接内存映射区:线性地址=3G+物理地址。从3G开始,最大896M的线性地址区间,我们称作直接内存映射区,这是因为该区域的线性地址和物理地址之间存在线性转换关系。

2、动态内存映射区:最小120M。由内核函数vmalloc()来分配。线性空间连续,物理空间不一定连续。分配一段虚拟地址,仅仅是一个地址,并不对应实际的物理地址。分配的虚拟地址在动态内存映射区,但可能处于低端内存,也可能处于高端内存(因为直接映射区最大为896M)。

3、永久内存映射区:4M。(PKMAP)896M以上的高端内存,可以使用该区域来访问。访问方法:

1)使用alloc_page(__GFP_HIGHMEM)分配高端内存页(得到物理页)

2)使用kmap函数将分配到的高端内存映射到该区域。(得到线性地址)

4、固定内存映射区:4M。每个地址项都服务于特定的用途,如ACPI_BASE等。映射关系做好了,不能改变。

4-4-4内核链表(参考课件)

链表数据结构:一般包含两个域:数据域和指针域。

链表数据结构的定义:

struct list_head

{

struct list_head *next,*prev;

}

内核链表具备双链表功能,通常它都组织成双向循环链表,在[include/linux/list.h]中。

传统链表和linux链表的比较:

1、传统链表:单向链表,指针指向下一节点,指针为下一节点数据类型的指针。

缺点,节点类型变化,则指针类型也要变化,不通用。

2、linux链表:双向循环链表,指针类型固定为struct list_head,链表头也为struct list_head

类型,但是不含数据。通用。

1、初始化链表头

INIT_LIST_HEAD(list_head *head)

2、插入节点

list_add(struct list_head *new,struct list_head *head):插入的节点位于head之后。

list_add_tail(struct list_head *new,struct list_head *head):插入的节点位于链表尾。

3、删除节点

list_del(struct list_head *entry):entry为要删除的节点。

4、提取数据结构

list_entry(ptr,type,member)

根据已知的数据结构中的节点指针ptr,找出数据结构和数据。

ptr:指向本节点struct list_head结构的指针

type:要提取的数据的类型(包含struct list_head结构和数据)

member:struct list_head结构在整个数据结构中的成员名

返回值:指向整个数据结构的指针。

例如:list_entry(aup,struct autofs,list)

5、遍历链表——list_for_each和list_for_each_safe

list_for_each(struct list_head *pos,struct list_head *head):实际上是一个循环,是一个宏。

head:指定要遍历哪一个链表;

pos:获取值,每一次遍历时指向不同的节点的list_head,第一次指向第一个节点。

例如:

struct list_head *entry;

struct list_head cs46xx_devs;//链表头

srtuct cs_card card;

list_for_each(entry,&cs46xx_devs)

{

card = list_entry(entry,srtuct cs_card,list); //寻找srtuct cs_card类型的结构

if(card->dev_midi = = minor) //利用srtuct cs_card类型结构的指针再访问里面的数据break;

}

编译在arm平台运行的内核模块时,makefile的编写:

ifneq ($(KERNELRELEASE),)

obj-m := myhello.o //编译多个内核模块时直接在后面加

myhello-objs := file1.o file2.o file3.o

else

KDIR := /lib/modules/2.6.18-53.el5/build //指定内核模块所依赖的内核源代码(运行环境)all:

make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-

//其他都一样,就这里不一样

clean:

rm -f *.ko *.o *.mod.o *.mod.c *.symvers

endif

4-4-5内核定时器(参考课件)

时钟中断:由系统的定时硬件以周期性的时间间隔产生,这个时间间隔(即频率)由内核根据HZ来确定,HZ是一个与体系结构无关的常数,默认值为1000。

Jiffies:(unsigned long)每当时钟中断发生时,全局变量jiffies就加1。

(jiffies记录了linux系统自启动发生时钟中断的次数),可以用来计算时间间隔。例如:

unsigned long j=jiffies + jit_delay*HZ;

while(jiffies

{

/*do nothing*/ //延时jit_delay秒

}

内核定时器的作用:

用于控制某个函数(定时器处理函数)在未来的某个特定的时间执行。

内核定时器注册的处理函数只执行一次,

通过使用内核函数mod_timer修改超时时间,可以实现多次使用内核定时器。

struct timer_list结构:

一个struct timer_list结构只描述一个内核定时器(内核定时器被组织成双向链表)。

struct timer_list

{

struct list_head entry; //内核使用,用来串连定时器链表。

unsigned long expires; //超时的jiffies的值,指定定时器在何时超时

void (*function)(unsigned long); //超时处理函数

unsigned long data; //超时处理函数的参数

struct tevc_base *base; //内核使用

}

初始化定时器分为两个步骤:1、内核使用的两个参数不用管,2、其他三个参数需要在,初始化定时器队列结构之后,启动定时器之前,自己去初始化的。

操作定时器有如下函数:

1、void init_timer(struct timer_list *timer);

初始化定时器队列结构

2、void add_timer(struct timer_list *timer);

启动定时器

3、int del_timer(struct timer_list *timer);

在定时器超时之前将它删除。当定时器超时后,系统会自动地将它删除。

linux内核之内存管理

Linux内核之内存管理 作者:harvey wang 邮箱:harvey.perfect@https://www.360docs.net/doc/0e5299199.html, 新浪博客地址:https://www.360docs.net/doc/0e5299199.html,/harveyperfect,有关于减肥和学习英语相关的博文,欢迎交流 把linux内存管理分为下面四个层面 (一)硬件辅助的虚实地址转换 (二)内核管理的内存相关 (三)单个进程的内存管理 (四)malloc软件 (一)处理器硬件辅助的虚实地址转换(以x86为例) 在x86中虚实地址转换分为段式转换和页转换。段转换过程是由逻辑地址(或称为虚拟地址)转换为线性地址;页转换过程则是将线性地址转换为物理地址。段转换示意图如下 X86支持两种段,gdt和ldt(全局描述段表和局部描述符段表),在linux中只使用了4个全局描述符表,内核空间和用户空间分别两个gdt,分别对应各自的代码段和数据段。也可以认为在linux中变相地disable了x86的段式转换功能。 页转换示意图如下

在linux中x86 的cr3寄存器(页表基地址寄存器)保存在进程的上下文中,在进程切换时会保存或回复该寄存器的内容,这样每个进程都有自己的转换页表,从而保证了每个进程有自己的虚拟空间。 (二)内核管理的内存相关 从几个概念展开内存管理:node、zone、buddy、slab 1、Node SGI Altix3000系统的两个结点 如上图,NUMA系统的结点通常是由一组CPU(如,SGI Altix 3000是2个Itanium2 CPU)和本地内存组成。由于每个结点都有自己的本地内存,因此全系统的内存在物理上是分布的,每个结点访问本地内存和访问其它结点的远地内存的延迟是不同的,为了优化对NUMA 系统的支持,引进了Node 来将NUMA 物理内存进行划分为不同的Node。而操作系统也必须能感知硬件的拓扑结构,优化系统的访存。

linux内存管理子系统 笔记

4-4 linux内存管理子系统 4-4-1 linux内存管理(参考课件) 物理地址:cpu地址总线上寻址物理内存的地址信号,是地址变换的最终结果 逻辑地址:程序代码经过编译后,出现在汇编程序中的地址(程序设计时使用的地址) 线性地址:又名虚拟地址,32位cpu架构下4G地址空间 CPU要将一个逻辑地址转换为物理地址,需要两步: 1、首先CPU利用段式内存管理单元,将逻辑地址转换成线性地址; 2、再利用页式内存管理单元,把线性地址最终转换为物理地址 相关公式: 逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)(通用的) 16位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 线性地址=段寄存器的值×16+逻辑地址的偏移部分 物理地址=线性地址(没有页式管理) 32位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 线性地址=段寄存器的值+逻辑地址的偏移部分 物理地址<——>线性地址(mapping转换) ARM32位:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 逻辑地址=段内偏移量(段基地址为0) 线性地址=逻辑地址=段内偏移量(32位不用乘以32) 物理地址<——>线性地址(mapping转换) ************************!!以下都是x86模式下!!********************************* 一、段式管理 1.1、16位CPU:(没有页式管理) 1.1.1、段式管理的由来: 16位CPU内部有20位地址总线,可寻址2的20次方即1M的内存空间,但16位CPU 只有16位的寄存器,因此只能访问2的16次方即64K。因此就采用了内存分段的管理模式,在CPU内部加入了段寄存器,这样1M被分成若干个逻辑段,每个逻辑段的要求如下: 1、逻辑段的起始地址(段地址)必须是16的整数倍,即最后4个二进制位须全是0 (因此不必保存)。 2、逻辑段的最大容量为64K。 1.1.2、物理地址的形成方式: 段地址:将段寄存器中的数值左移4位补4个0(乘以16),得到实际的段地址。 段偏移:在段偏移寄存器中。 1)逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 2)由逻辑地址得到物理地址的公式为:(因为没有页式管理,所以这一步就得到了物理地址)物理地址PA=段寄存器的值×16+逻辑地址的偏移部分(注意!!)(段与段可能会重叠)

《深入理解LINUX内存管理》学习笔记.

引子 为什么要写这个笔记: 1,这本书的中文版翻译了太垃圾,没法阅读。阅读英文原版,可以很好的理解作者的思路。作此笔记备忘 2,一直以来学习LINUX kernel的知识缺乏系统化,借对这本书的学习,系统化的学习一下LINUX kernel。 3,自己一直在做一个too small,too simple的单进程,特权模式,64bit保护模式的称不上OS的OS,已经做完了bootloader, 构思kernel的实现的时候,困惑在内存管理的实现上,阅读这本书,希望能有利于自己的OS的编写。 4,克服惰性,多读书,希望一天能阅读5页,争取半年内阅读完这本原版700多页的巨著。 不足: 我不可能完全理解LINUX 内存管理的精髓,肯定有很多地方理解错误。希望大家能够指正,以便提高,谢谢。 学习方法: 可能您第一次阅读的时候很多地方都不理解,不用担心。那您可能需要阅读一些文件系统的知识。 或者阅读全部笔记后,再回头阅读,有些地方您就理解了。 言归正传: 一、概要 可用工具 CodeViz: 生成代码调用关系图的工具,这个工具我现在还没有去使用,有兴趣的可以自己试试去建立调用关系图。 http://www.csn.ul.ie/~mel/projects/codeviz/ Linux cross reference (LXR): 以web的方式阅读和查找LINUX内核源代码的工具。这个工具安装相当麻烦,我建议直接到它的官方网站直接读代码。 http://lxr.linux.no/linux+v2.6.24/ 模块 LINUX内存管理代码模块主要分为4个部分: 1.Out of memory 代码在mm/oom_kill.c 貌似用于杀进程的时候对内存的操作 2.虚拟内存的分配代码在mm/vmalloc.c

Linux内存管理实验

1 《unix 操作系统教程》课程实验报告 实验名称 Linux 内存管理实验 实验序号 5 姓 名 系院专业 班 级 学 号 实验日期 2012.11.28 指导教师 成 绩 一、实验目的 1. 通过在Linux 环境下对内存管理的基本操作,感性认识Linux 如何对内存进行管理。 2. 利用readelf 和objdump 观测 linux 下的内存地址映射过程以及进程的虚拟地址空间。 二、实验内容与要求 (1)按照实验内容完成实验操作步骤,学习内存管理中的一些常用命令 (2)理解linux 中逻辑地址、线性地址的概念。 (3)提交实验报告。 三、实验设备 地点: 实验实训中心A4-2 设备:计算机一台 linux 操作系统

2 四、实验步骤与测试 实验一 free 命令显示显示内存的使用情况(使用的和空闲的),包括物理内存、交换区内存、内核缓冲区内存。不包括共享内存。free 命令默认选项为-k 语法: free [-bkmotV] [-s <间隔秒数>]选项介绍: -b: 以Byte 为单位显示内存使用情况; -k: 以KB 为单位显示内存使用情况; -m: 以MB 为单位显示内存使用情况; -o: 不显示缓冲区调节列; -s<间隔秒数>: 每间隔指定时间执行一次free 命令; -t: 显示内存总和列; -V: 显示版本信息; (1)free -k: 以KB 为单位显示内存使用情况; 解释:total: 内存总量: 3355508(k) used: 已经使用的内存量: 490664(k) free: 空闲的内存量: 2864844(k) shared: 当前已经废弃不用,总量是0(k) buffers: 25164(k) Buffer Cache 内存量: 263480(k) cached: Page Cache 内存量: 21436(k) (2)free –m -s 5:以M 为单位,5秒显示以下内存信息 解释:以上为每隔5秒显示内存信息,由以上图可知:两次内存使用情况没有变化。 (3)free -o: 不显示缓冲区调节列; 解释:由以上可知Buffer Cache 这一列没有显示出来。 (4)free -t: 显示内存总和列;

Linux操作系统内存管理

Linux操作系统内存管理 摘要: Linux支持虚拟内存, 就是使用磁盘作为RAM的扩展,使可用内存相应地有效扩大。核心把当前不用的内存块存到硬盘,腾出内存给其他目的。当原来的内容又要使用时,再读回内存。这对用户全透明:运行于Linux的程序只看到大量的可用内存而不甘心哪部分在磁盘上。当然,读写硬盘比真的内存慢(慢千倍),所以程序运行较慢。用做虚拟内存的这部分硬盘叫对换空间。 Linux可以使用文件系统中的普通文件或单独的分区作为对换空间。对换分区更快,但对换文件更易于改变大小(无须对硬盘重分区)。如果知道要多少对换空间,应该用对换分区;如果不能确认,可以先用对换文件,用一段时间后再根据所需空间建立对换分区。 Linux允许同时使用多个对换分区和/或对换文件。即如果偶尔需要更多的对换空间,可以随时建立一个额外的对换文件。 Linux是一个遵循POSIX(Portable Operating System Interface)标准的操作系统,它继承了UNIX系统优秀的设计思想,拥有简练、容错强、高效而且稳定的内核。此外Linux还具备其他操作系统所不能比拟的优点。①:完全免费; ②:内核源代码完全公开。 Linux内核拥有一个功能完备的内存管理子系统,它增加了对NUMA(非均匀存储结构)体系结构的支持并且使用了基于区(ZONE)的物理内存管理方法,从而保持了物理上连续分布、而逻辑上统一的内存模式和传统的共享内存编程模型,使得系统的性能得以极大的扩展。这样Linux不仅能够满足传统的桌面应用,而且还能满足高端服务器市场的需要。目前,Linux不仅在Internet服务器上表现出色,而且还可以胜任大型数据库系统的服务器。 关键字:虚拟内存,物理内存管理,虚拟内存管理 一、Linux存储管理的基本框架 Linux内核采用虚拟页式存储管理,采用三次映射机制实现从线性地址到物理地址的映射。其中PGD为页面目录,PMD为中间目录,PT为页面表。具体的映射过程为: ⑴从CR3寄存器中找到PGD基地址; ⑵以线性地址的最高位段为下标,在PGD中找到指向PMD的指针;

LINUX系统基本的内存管理知识讲解

内存是Linux内核所管理的最重要的资源之一。内存管理系统是操作系统中最为重要的部分,因为系统的物理内存总是少于系统所需要的内存数量。虚拟内存就是为了克服这个矛盾而采用的策略。系统的虚拟内存通过在各个进程之间共享内存而使系统看起来有多于实际内存的内存容量。Linux支持虚拟内存, 就是使用磁盘作为RAM的扩展,使可用内存相应地有效扩大。核心把当前不用的内存块存到硬盘,腾出内存给其他目的。当原来的内容又要使用时,再读回内存。 一、内存使用情况监测 (1)实时监控内存使用情况 在命令行使用Free命令可以监控内存使用情况 代码如下: #free total used free shared buffers cached Mem: 256024 192284 63740 0 10676 101004 -/+ buffers/cache: 80604 175420 Swap: 522072 0 522072 上面给出了一个256兆的RAM和512兆交换空间的系统情况。第三行输出(Mem:)显示物理内存。total列不显示核心使用的物理内存(通常大约1MB)。used列显示被使用的内存总额(第二行不计缓冲)。 free列显示全部没使用的内存。Shared列显示多个进程共享的内存总额。Buffers列显示磁盘缓存的当前大小。第五行(Swap:)对对换空间,显示的信息类似上面。如果这行为全0,那么没使用对换空间。在缺省的状态下,free命令以千字节(也就是1024字节为单位)来显示内存使用情况。可以使用—h参数以字节为单位显示内存使用情况,或者可以使用—m参数以兆字节为单位显示内存使用情况。还可以通过—s 参数使用命令来不间断地监视内存使用情况: #free –b –s2 这个命令将会在终端窗口中连续不断地报告内存的使用情况,每2秒钟更新一次。 (2)组合watch與 free命令用来实时监控内存使用情况: 代码如下: #watch -n 2 -d free

linux内存管理实验报告

操作系统实验报告 院别:XXXXXX 班级:XXXXXX 学号:XXXXXX 姓名:稻草人

实验题目:内存管理实验 一、实验目的 1、通过本次试验体会操作系统中内存的分配模式; 2、掌握内存分配的方法(FF,BF,WF); 3、学会进程的建立,当一个进程被终止时内存是如何处理被 释放块,并当内存不满足进程申请时是如何使用内存紧 凑; 4、掌握内存回收过程及实现方法; 5、学会进行内存的申请释放和管理; 二、实验内容 附源代码: /*宏定义*/ #include #include #include #define PROCESS_NAME_LEN 32 /*进程名称的最大长度*/ #define MIN_SLICE 10 /*最小碎片的大小*/ #define DEFAULT_MEM_SIZE 1024 /*默认内存的大小*/ #define DEFAULT_MEM_START 0 /*默认内存的起始位置*/ /* 内存分配算法 */ #define MA_FF 1 #define MA_BF 2 #define MA_WF 3 int mem_size=DEFAULT_MEM_SIZE; /*内存大小*/ int ma_algorithm = MA_FF; /*当前分配算法*/ int flag = 0; /*设置内存大小标志*/ static int pid = 0; /*初始pid*/ int algorithm;

/*描述每一个空闲块的数据结构*/ struct free_block_type{ int size; int start_addr; struct free_block_type *next; }; /*指向内存中空闲块链表的首指针*/ struct free_block_type *free_block; /*每个进程分配到的内存块的描述*/ struct allocated_block{ int pid; int size; int start_addr; char process_name[PROCESS_NAME_LEN]; struct allocated_block *next; }; /*进程分配内存块链表的首指针*/ struct allocated_block *allocated_block_head = NULL; struct allocated_block *find_process(int id) { struct allocated_block *p; p=allocated_block_head; while(p!=NULL) { if (p->pid==id) return p; } return NULL; } void swap(int *p,int *q) { int temp; temp = *p; *p = *q; *q = temp; return;

Linux 内存管理导读

Linux 内存管理导读 1. 存储层次结构和x86存储管理硬件(MMU) 1.1存储层次 高速缓存(cache) à主存(main memory) à磁盘(disk) 理解存储层次结构的根源:CPU速度和存储器速度的差距。 层次结构可行的原因:局部性原理。 LINUX的任务: l减小footprint,提高cache命中率,充分利用局部性。 l实现虚拟存储以满足进程的需求,有效地管理内存分配,力求最合理地利用有限的资源。 1.2 MMU的作用 辅助操作系统进行内存管理,提供虚实地址转换等硬件支持。 1.3 x86的地址 逻辑地址:出现在机器指令中,用来制定操作数的地址。段:偏移 线性地址:逻辑地址经过分段单元处理后(如将段地址左移四位与偏移量)得到线性地址,这是一个32位的无符号整数,可用于定位4G个存储单元。 物理地址:线性地址经过页表查找后得出物理地址,这个地址将被送到地址总线上指示所要访问的物理内存单元。 LINUX: 尽量避免使用段功能以提高可移植性。如通过使用基址为0的段, 使逻辑地址==线性地址。 1.4 x86的段与Linux下的段比较 x86保护模式下的段:表索引+描述符项。不仅仅是一个基地址的原因是为了提供更多的信息:保护、长度限制、类型等。描述符项存放在一张表中(GDT或LDT),表索引就是表的索引。段寄存器中存放的是表索引,在段寄存器装入的同时,描述符中的数据被装入一个不可见的寄存器以便cpu快速访问。 专用寄存器:GDTR(包含全局描述附表的首地址), LDTR(当前进程的段描述附表首地址), TSR(指向当前进程的任务状态段) LINUX使用的四种段: __KERNEL_CS:内核代码段。范围0-4G。可读、执行。DPL=0。 __KERNEL_DS:内核代码段。范围0-4G。可读、写。DPL=0。 __USER_CS:内核代码段。范围0-4G。可读、执行。DPL=3。 __USER_DS:内核代码段。范围0-4G。可读、写。DPL=3。 TSS(任务状态段):存储进程的硬件上下文,进程切换时使用。(因为x86硬件对TSS有一定支持,所有有这个特殊的段和相应的专用寄存器。) __USER_CS和__USER_DS段都是被所有在用户态下的进程共享的。但这种段的共享和进程空间的共享是有区别的:虽然各个进程使用同一个(种)段,但通过使

Linux内存管理初始化

Linux内存管理初始化 内存管理子系统是linux内核最核心最重要的一部分,内核的其他部分都需要在内存管理子系统的基础上运行。而对其初始化是了解整个内存管理子系统的基础。对相关数据结构的初始化是从全局启动例程start_kernel开始的。本文详细描述了从bootloader跳转到linux 内核内存管理子系统初始化期间所做的操作,从而来加深对内存管理子系统知识的理解和掌握。 内核的入口是stext,这是在arch/arm/kernel/vmlinux.lds.S中指定的。而符号stext是在arch/arm/kernel/head.S中定义的。整个初始化分为两个阶段,首先是在head.S中用汇编代码执行一些平台相关的初始化,完成后跳转到start_kernel函数用C语言代码执行剩余的通用初始化部分。整个初始化流程图如下图所示: 一、启动条件 通常从系统上电到运行到linux kenel这部分的任务是由bootloader来完成。Boot loader在跳转到kernel之前要完成一些限制条件: 1、CPU必须处于SVC(supervisor)模式,并且IRQ和FIQ中断必须是禁止的;

2、MMU(内存管理单元)必须是关闭的, 此时虚拟地址对应物理地址; 3、数据cache(Data cache)必须是关闭的; 4、指令cache(Instructioncache)没有强制要求; 5、CPU通用寄存器0(r0)必须是0; 6、CPU通用寄存器1(r1)必须是ARM Linuxmachine type; 7、CPU通用寄存器2(r2)必须是kernelparameter list的物理地址; 二、汇编代码初始化部分 汇编代码部分主要完成的工作如下所示,下文只是概述head.S中各个函数完成的主要 功能,具体的技术细节,本文不再赘述。 ? 确定processortype ? 确定machinetype ? 创建页表 ? 调用平台特定的__cpu_flush函数 ? 开启mmu ? 切换数据 ? 最终跳转到start_kernel 三、C语言代码初始化部分 C语言代码初始化部分主要负责建立结点和内存域的数据结构、初始化页表、初始化用 于内存管理的伙伴系统。在启动过程中,尽管内存管理模块尚未初始化完成,但内核仍然需要分配内存以创建各种数据结构。bootmem分配器用于在启动阶段分配内存。所有涉及的实现都是在start_kernel函数中实现的,其中涉及到内存初始化的函数如下: 1、build_all_zonelist用于结点和内存域的初始化。

Linux操作系统内存管理

Linux 操 作 系 统 内 存 管 理 学院:信息工程 姓名:张卫莉 班级:信管二班 学号:100301238

摘要: Linux支持虚拟内存, 就是使用磁盘作为RAM的扩展,使可用内存相应地有效扩大。核心把当前不用的内存块存到硬盘,腾出内存给其他目的。当原来的内容又要使用时,再读回内存。这对用户全透明:运行于Linux的程序只看到大量的可用内存而不甘心哪部分在磁盘上。当然,读写硬盘比真的内存慢(慢千倍),所以程序运行较慢。用做虚拟内存的这部分硬盘叫对换空间。 Linux可以使用文件系统中的普通文件或单独的分区作为对换空间。对换分区更快,但对换文件更易于改变大小(无须对硬盘重分区)。如果知道要多少对换空间,应该用对换分区;如果不能确认,可以先用对换文件,用一段时间后再根据所需空间建立对换分区。 Linux允许同时使用多个对换分区和/或对换文件。即如果偶尔需要更多的对换空间,可以随时建立一个额外的对换文件。 Linux是一个遵循POSIX(Portable Operating System Interface)标准的操作系统,它继承了UNIX系统优秀的设计思想,拥有简练、容错强、高效而且稳定的内核。此外Linux还具备其他操作系统所不能比拟的优点。①:完全免费;②:内核源代码完全公开。 Linux内核拥有一个功能完备的内存管理子系统,它增加了对NUMA(非均匀存储结构)体系结构的支持并且使用了基于区(ZONE) 的物理内存管理方法,从而保持了物理上连续分布、而逻辑上统一的内存模式和传统的共享内存编程模型,使得系统的性能得以极大的扩展。这样Linux不仅能够满足传统的桌面应用,而且还能满足高端服务器市场的需要。目前,Linux不仅在Internet服务器上表现出色,而且还可以胜任大型数据库系统的服务器。

Linux内存管理

Linux内存管理:页表、页式内存管理机制 一. CPU的页式内存管理(硬件) CPU的页式内存管理单元,负责把一个线性地址,最终翻译为一个物理地址。从管理和效率的角度出发,线性地址被分为以固定长度为单位的组,称为页(page),例如一个32位的机器,线性地址最大可为4G,可以用4KB为一个页来划分,这页,整个线性地址就被划分为一个tatol_page[2^20]的大数组,共有2的20个次方个页。这个大数组我们称之为页目录。目录中的每一个目录项,就是一个地址——对应的页的地址。(虚拟内存地址) 另一类“页”,我们称之为物理页,或者是页框、页桢的。是分页单元把所有的物理内存也划分为固定长度的管理单位,它的长度一般与内存页是一一对应的。(物理内存管理) 这里注意到,这个total_page数组有2^20个成员,每个成员是一个地址(32位机,一个地址也就是4字节),那么要单单要表示这么一个数组,就要占去4MB的内存空间。为了节省空间,引入了一个二级管理模式的机器来组织分页单元。文字描述太累,看图直观一些: 如上图, 1、分页单元中,页目录是唯一的,它的地址放在CPU的cr3寄存器中,是进行地址转换的开始点。万里长征就从此长始了。 2、每一个活动的进程,因为都有其独立的对应的虚似内存(页目录也是唯一的),那么它也对应了一个独立的页目录地址。——运行一个进程,需要将它的页目录地址放到cr3寄存器中,将别个的保存下来。 3、每一个32位的线性地址被划分为三部份,面目录索引(10位):页表索引(10位):偏移(12位) 依据以下步骤进行转换: 1、从cr3中取出进程的页目录地址(操作系统负责在调度进程的时候,把这个地址装入对应寄存器); 2、根据线性地址前十位,在数组中,找到对应的索引项,因为引入了二级管理模式,页目录中的项,不再是页的地址,而是一个页表的地址。(又引入了一个数组),页的地址被放到页表中去了。 3、根据线性地址的中间十位,在页表(也是数组)中找到页的起始地址; 4、将页的起始地址与线性地址中最后12位相加,得到最终我们想要的葫芦; 这个转换过程,应该说还是非常简单地。全部由硬件完成,虽然多了一道手续,但是节约了大量的内存,还是值得的。那么再简单地验证一下: 1、这样的二级模式是否仍能够表示4G的地址; 页目录共有:2^10项,也就是说有这么多个页表

Linux物理内存管理概述

在内核态申请内存比在用户态申请内存要更为直接,它没有采用用户态那种延迟分配内存技术。内核认为一旦有内核函数申请内存,那么就必须立刻满足该申请内存的请求,并且这个请求一定是正确合理的。相反,对于用户态申请内存的请求,内核总是尽量延后分配物理内存,用户进程总是先获得一个虚拟内存区的使用权,最终通过缺页异常获得一块真正的物理内存。 1.物理内存的内核映射 IA32架构中内核虚拟地址空间只有1GB大小(从3GB到4GB),因此可以直接将1GB大小的物理内存(即常规内存)映射到内核地址空间,但超出1GB大小的 物理内存(即高端内存)就不能映射到内核空间。为此,内核采取了下面的方法使得内核可以使用所有的物理内存。 1.高端内存不能全部映射到内核空间,也就是说这些物理内存没有对应的线性地址。不过,内核为每个物理页框都分配了对应的页框描述符,所有的页框描述符都保存在mem_map数组中,因此每个页框描述符的线性地址都是固定存在的。内核此时可以使用alloc_pages()和alloc_page()来分配高端内存,因为这些函数返回页框描述符的线性地址。 2.内核地址空间的后128MB专门用于映射高端内存,否则,没有线性地址的高端内存不能被内核所访问。这些高端内存的内核映射显然是暂时映射的,否则也只能映射128MB的高端内存。当内核需要访问高端内存时就临时在这个区域进行地址映射,使用完毕之后再用来进行其他高端内存的映射。 由于要进行高端内存的内核映射,因此直接能够映射的物理内存大小只有 896MB,该值保存在high_memory中。内核地址空间的线性地址区间如下图所示:

从图中可以看出,内核采用了三种机制将高端内存映射到内核空间:永久内核映射,固定映射和vmalloc机制。 2.物理内存管理机制 基于物理内存在内核空间中的映射原理,物理内存的管理方式也有所不同。内核中物理内存的管理机制主要有伙伴算法,slab高速缓存和vmalloc机制。其中伙伴算法和slab高速缓存都在物理内存映射区分配物理内存,而vmalloc机制则在高端内存映射区分配物理内存。 伙伴算法 伙伴算法负责大块连续物理内存的分配和释放,以页框为基本单位。该机制可以避免外部碎片。 per-CPU页框高速缓存 内核经常请求和释放单个页框,该缓存包含预先分配的页框,用于满足本地CPU 发出的单一页框请求。 slab缓存 slab缓存负责小块物理内存的分配,并且它也作为高速缓存,主要针对内核中经常分配并释放的对象。 vmalloc机制

Linux内存管理中的Slab分配机制

现 代计算机!总第二三五期" MODERNCOMPUTER2006.5 实践与经验 1Linux内存管理体系 在Intel80x86体系结构中,Linux内核的内存管 理采用了分页管理方式,真正实现了虚拟存储器管理,其虚拟内存管理的实现结构如图1所示。 图1 内存映射模块负责把磁盘文件的逻辑地址映射到虚拟地址,把虚拟地址映射到物理地址;交换模块负责控制内存内容的换入和换出;核心管理模块负责核心内存管理功能,即对页的分配、 回收、释放及请页处理等;结构特定的模块负责给各种硬件提供通用接口,这个模块通过执行命令来改变硬件MMU的虚拟地址映射。 Linux虚拟内存的实现机制为:内存管理程序通过映射机制把用户程序的逻辑地址映射到物理地址,在用户程序运行时如果发现程序中要用到的虚地址没有对应的物理内存时,就发出了请页要求;如果有空闲的内存可供分配,就请求分配内存,并把正在使 用的物理页纪录在页缓存中。如果没有足够的内存可供分配,那么就调用交换机制,腾出一部分内存。另外,在地址映射中要通过TLB来寻找物理页,交换机制中也要用到交换缓存,并且把物理页内容交换到交换文件后也要修改页表来映射文件地址。 2Slab分配机制概述 Slab分配机制用来对内存区域中内核空间进行 分配和回收。Slab使用对象来组织内存区域,对象就是指存放一组数据结构的内存区。Slab根据内存区的使用频率对内存区域进行划分。对于预期频繁使用的内存区,Slab创建一组特定大小的专用缓冲区进行处理,以避免内碎片的产生;对于较少使用的内存区, Slab创建一组通用缓冲区来处理,即使这种处理模式产生碎片,对整个系统的性能影响也不大。 Slab分配模式把对象分组放进缓冲区,Slab缓冲区并非由各个对象直接构成,而是由一连串的Slab构成,而每个大块中则包括了若干个同种类型的对象。 高速缓存、Slab及对象之间的关系如图2所示。 图2 Linux内存管理中的Slab分配机制 赵鲲鹏1 , 苏葆光2 (1.长安大学,西安710061;2.浙江万里学院,宁波315101) 摘 要:早期Linux的内存分配机制采用伙伴算法,当请求分配的内存大小为几十个字节或几百个 字节时会产生内存碎片,严重消耗系统资源。现今采用Slab机制可以缓存物理空间的申请和回收,杜绝外部碎片的产生,降低内部碎片量。本文分析了Slab内存分配机制及其数据结构和接口函数,然后给出了Slab机制的实现。 关键词:Slab;内存管理;Linux;分配机制 ! "

相关主题
相关文档
最新文档