导航:首页 > 操作系统 > linux内存映射查看

linux内存映射查看

发布时间:2022-09-24 02:16:56

Ⅰ 详解linux系统内存知识及调优方案

内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。内存作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行。对于整个操作系统来说,内存可能是最麻烦的的设备。而其性能的好坏直接影响着整个操作系统。

我们知道CPU是不能与硬盘打交道的,只有数据被载入到内存中才可以被CPU调用。cpu在访问内存的时候需要先像内存监控程序请求,由监控程序控制和分配内存的读写请求,这个监控程序叫做MMU(内存管理单元)。下面以32位系统来说明内存的访问过程:

32位的系统上每一个进程在访问内存的时候,每一个进程都当做自己有4个G的内存空间可用,这叫虚拟内存(地址),虚拟内存转化成物理内存是通过MMU来完成的。为了能够从线性地址转换成物理地址,需要page table(页表)的内存空间,page table要载入到MMU上。为了完成线性地址到物理地址的映射,如果按照1个字节1个字节映射的话,需要一张非常大的表,这种转换关系会非常的复杂。因此把内存空间又划分成了另外一种存储单元格式,通常为4K。在不同的硬件平台上,它们的大小一般是不一样的,像x86 32位的有4k的页;而64位的有4k页,2M页,4M页,8M页等等,默认都是4k的。每一个进程一般而言都有自己的页路径和页表映射机制,不管那一个页表都是由内核加载的。每一个进程只能看到自己的线性地址空间,想要增加新的内存的时候,只能在自己的线性地址空间中申请,并且申请后一定是通过操作系统的内核映射到物理地址空间中去找那么一段空间,并且告诉线性地址空间准备好了,可以访问,并且在page table中增加一条映射关系,于是就可以访问物理内存了,这种叫做内存分配。但是新的申请一定是通过操作的内核到物理内存中去找那么一段空间,并且告诉线性地址空间好了,可以建设映射关系,最终page table建立映射关系。

这反映了上述描述过程的大体情况。可以看到每一个用户程序都会有自己的页表,并且映射到对应的主存储器上去。

根据上述文字和图表的描述可以发现2个问题:

1.每个进程如果需要访问内存的时候都需要去查找page table的话,势必会造成服务器的性能底下

2.如果主存储器的内存满了以后,应用程序还需要调用内存的时候怎么办

对于第一个问题,我们就需要借助TLB(Translation Lookaside Buffer)翻译后备缓冲器。TLB是一个内存管理单元,它可以用于改进虚拟地址到物理地址转换速度的缓存。这样每次在查找page table的时候就可以先去TLB中查找相应的页表数据,如果有就直接返回,没有再去查找page table,并把查找到的结果缓存中TLB中。TLB虽然解决了缓存的功能,但是在那么page table中查找映射关系仍然很慢,所以又有了page table的分级目录。page table可以分为1级目录,2级目录和偏移量

但是一个进程在运行的时候要频繁的打开文件,关闭文件。这就意味着要频繁的申请内存和释放内存。有些能够在内存中缓存数据的那些进程,他们对内存的分配和回收更多,那么每一次分配都会在页表中建立一个对应项。所以,就算内存的速度很快,大量频繁的同一时间分配和释放内存,依然会降低服务器的整体性能。当然内存空间不够用的时候,我们称为oom(out of memory,内存耗尽)。当内存耗尽的时候,,整个操作系统挂了。这种情况下我们可以考虑交换分区,交换分区毕竟是由硬盘虚拟出来的内存,所以其性能与真正的内存相比,差了很多,所以要尽力避免使用交换分区。有物理内存空间的时候尽量保证全部使用物理内存。cpu无论如何是不能给交换内存打交道的,它也只能给物理内存打交道,能寻址的空间也只能是物理内存。所以当真正物理内存空间不够用的时候,会通过LRU算法把其中最近最少使用的内存放到交换内存中去,这样物理内存中的那段空间就可以供新的程序使用了。但是这样会引发另外的一个问题,即原来的进程通过page table寻找的时候,那一段空间的数据已经不属于它了。所以此刻cpu发送通知或者异常告诉这个程序,这个地址空间已不属于它,这个时候可能会出现2种情况:

1.物理内存有可用的空间可用:这个时候cpu会根据以前的转换策略会把交换分区中的那段内存重新送到物理内存中去,但是转换过来的空间地址不一定会是以前的那一段空间地址,因为以前的那一段空间地址可能已经被别人使用了。

2.物理内存没有可用的空间可用:这个时候依然会使用LRU算发把当前物理地址空间上最近最少使用的空间地址转换到交换内存中去,并把当前进程需要的这断在交换空间中的内存送到物理内存空间中去,并且重新建立映射关系。

上述通知或者异常出现的情况,通常叫做缺页异常。缺页异常也分为大异常和小异常两种。大异常就是访问的数据内存中没有,不的不去硬盘上加载,无论是从交换内存中还是直接从磁盘的某个文件系统上,反正需要从硬盘上去加载,这种异常加载需要很长时间。小异常就是进程之间通过共享内存,第二个进程访问的时候,查看本地的内存映射表没有,但是其它进程已经拥有了这个内存页,所以可以直接映射,这种异常加载需要的时间一般很短。

在操作系统开机的时候,每一个io设备都会像cpu申请一些列的随机端口,这种端口叫做io端口。在IBM PC体系结构中,I/O地址空间一共提供了65,536个8位的I/O端口。正是这些io端口的存在,cpu可以与io设备进行读写交互的过程。在执行读写操作时,CPU使用地址总线选择所请求的I/O端口,使用数据总线在CPU寄存器和端口之间传送数据。I/O端口还可以被映射到物理地址空间:因此,处理器和I/O设备之间的通信就可以直接使用对内存进行操作的汇编语言指令(例如,mov、and、or等等)。现代的硬件设备更倾向于映射I/O,因为这样处理的速度较快,并可以和DMA结合起来使用。这样io在和内存传数据的时候就不需要通过cpu,cpu把总线的控制权交给DMA,每次io传数据的时候就调用DMA一次,就把cpu给解放了出来。当数据传输完了以后,DMA通知给cpu中断一次。DMA在运行的时候对整个总线有控制权限,当cpu发现有其它进程需要使用总线的时候,二者就会产生争用。这个时候,在总线控制权的使用上,CPU和DMA具有相等的权限。只要CPU委托给了DMA,就不能随意的收回这个委托,就要等待DMA的用完。

如果没有其它进程可以运行,或者其它进程运行的时间非常短,这个时候CPU发现我们的IO仍然没有完成,那就意味着,CPU只能等待IO了。CPU在时间分配里面有个iowait的值,就是CPU在等待IO花费的时间。有些是在同步调用过程中,CPU必须要等待IO的完成;否者CPU可以释放IO的传输在背后自动完成,CPU自己去处理其它的事情。等硬盘数据传输完成以后,硬盘只需要像CPU发起一个通知即可。CPU外围有一种设备,这个设备叫做可编程中断控制器。每一个硬件设备为了给CPU通信,在刚开机的时候,在BIOS实现检测的时候,这个设备就要到可编程中断控制器上去注册一个所谓的中断号。那么这个号码就归这个硬件使用了。当前主机上可能有多个硬件,每一个硬件都有自己的号码,CPU在收到中断号以后,就能够通过中断相量表查找到那个硬件设备进行中断。并且就由对应的IO端口过来处理了。

CPU正在运行其它进程,当一个中断请求发过来的时候,CPU会立即终止当前正在处理的进程,而去处理中断。当前CPU挂起当前正在处理的进程,转而去执行中断的过程,也叫做中断切换。只不过,这种切换在量级别上比进程切换要低一些,而且任何中断的优先级通常比任何进程也要高,因为我们指的是硬件中断。中断还分为上半部和下半部,一般而言,上半部就是CPU在处理的时候,把它接进来,放到内存中,如果这个事情不是特别紧急(CPU或者内核会自己判断),因此在这种情况下,CPU回到现场继续执行刚才挂起的进程,当这个进程处理完了,再回过头来执行中断的下半部分。

在32位系统中,我们的内存(线性地址)地址空间中,一般而言,低地址空间有一个G是给内核使用的,上面3个G是给进程使用的。但是应该明白,其实在内核内存当中,再往下,不是直接这样划分的。32位系统和64位系统可能不一样(物理地址),在32位系统中,最低端有那么10多M的空间是给DMA使用的。DNA的总线宽度是很小的,可能只有几位,所以寻址能力很有限,访问的内存空间也就很有限。如果DMA需要复制数据,而且自己能够寻址物理内存,还可以把数据直接壮哉进内存中去,那么就必须保证DMA能够寻址那段内存才行。寻址的前提就是把最低地址断M,DA的寻址范围内的那一段给了DMA。所以站在这个角度来说,我们的内存管理是分区域的。

在32位系统上,16M的内存空间给了ZONE_DMA(DMA使用的物理地址空间);从16M到896M给了ZONE_NORMAL(正常物理地址空间),对于Linux操作系统来说,是内核可以直接访问的地址空间;从896M到1G这断空间叫做"Reserved"(预留的物理地址空间);从1G到4G的这段物理地址空间中,我们的内核是不能直接访问的,要想访问必须把其中的一段内容映射到Reserved来,在Reserved中保留出那一段内存的地址编码,我们内核才能上去访问,所以内核不直接访问大于1G的物理地址空间。所以在32位系统上,它访问内存当中的数据,中间是需要一个额外步骤的。

在64位系统上,ZONE_DAM给了低端的1G地址空间,这个时候DMA的寻址能力被大大加强了;ZONE_DAM32可以使用4G的空间;而大于1G以上给划分了ZONE_NORMAL,这段空间都可以被内核直接访问。所以在64位上,内核访问大于1G的内存地址,就不需要额外的步骤了,效率和性能上也大大增加,这也就是为什么要使用64位系统的原因。

在现在的PC架构上,AMD,INTER都支持一种机制,叫做PEA(物理地址扩展)。所谓PAE。指的是在32位系统的地址总线上,又扩展了4位,使得32位系统上的地址空间可以达到64G。当然在32为系统上,不管你的物理内存有多大,单个进程所使用的空间是无法扩展的。因为在32位的系统上,线性地址空间只有4个G,而单个进程能够识别的访问也只有3个G。

linux的虚拟内存子系统包含了以下几个功能模块:

slab allocator,zoned buddy allocator,MMU,kswapd,bdflush

slab allocator叫做slab分配器

buddy allocator又叫做buddy system,叫做伙伴系统,也是一种内存分配器

buddy system是工作在MMU之上的,而slab allocator又是工作在buddy system之上的。

设置为小于等于1G,在数据库服务器应该劲量避免使用交换内存

3.在应用服务器上,可以设置为RAM*0.5,当然这个是理论值

如果不的不使用交换内存,应该把交换内存放到最靠外的磁道分区上,因为最外边的磁盘的访问速度最快。所以如果有多块硬盘,可以把每块硬盘的最外层的磁道拿一小部分出来作为交换分区。交换分区可以定义优先级,因此把这些硬盘的交换内存的优先级设置为一样,可以实现负载均衡的效果。定义交换分区优先级的方法为编辑/etc/fstab:

/dev/sda1 swap swap pri=5 0 0

/dev/sdb1 swap swap pri=5 0 0

/dev/sdc1 swap swap pri=5 0 0

/dev/sdd1 swap swap pri=5 0 0

四.内存耗尽时候的相关调优参数

当Linux内存耗尽的时候,它会杀死那些占用内存最多的进程,以下三种情况会杀死进程:

1.所有的进程都是活动进程,这个时候想交换出去都没有空闲的进程

2.没有可用的page页在ZONE_NORMAL中

3.有其它新进程启动,申请内存空间的时候,要找一个空闲内存给做映射,但是这个时候找不到了

一旦内存耗尽的时候,操作系统就会启用oom-kill机制。

在/proc/PID/目录下有一个文件叫做oom_score,就是用来指定oom的评分的,就是坏蛋指数。

如果要手动启用oom-kill机制的话,只需要执行echo f>/proc/sysrq-trigger即可,它会自动杀掉我们指定的坏蛋指数评分最高的那个进程

可以通过echo n > /proc/PID/oom_adj来调整一个进程的坏蛋评分指数。最终的评分指数就是2的oom_adj的值的N次方。假如我们的一个进程的oom_adj的值是5,那么它的坏蛋评分指数就是2的5次方。

如果想禁止oom-kill功能的使用可以使用vm.panic_on_oom=1即可。

五.与容量有关的内存调优参数:

overcommit_memory,可用参数有3个,规定是否能够过量使用内存:

0:默认设置,内核执行启发式的过量使用处理

1:内核执行无内存的过量使用处理。使用这个值会增大内存超载的可能性

2:内存的使用量等于swap的大小+RAM*overcommit_ratio的值。如果希望减小内存的过度使用,这个值是最安全的

overcommit_ratio:将overcommit_memory指定为2时候,提供的物理RAM比例,默认为50

六.与通信相关的调优参数

常见在同一个主机中进行进程间通信的方式:

1.通过消息message;2.通过signal信号量进行通信;3.通过共享内存进行通信,跨主机常见的通信方式是rpc

以消息的方式实现进程通信的调优方案:

msgmax:以字节为单位规定消息队列中任意消息的最大允许大小。这个值一定不能超过该队列的大小(msgmnb),默认值为65536

msgmnb:以字节为单位规定单一消息队列的最大值(最大长度)。默认为65536字节

msgmni:规定消息队列识别符的最大数量(及队列的最大数量)。64位架构机器的默认值为1985;32位架构机器的默认值为1736

以共享内存方式实现进程通信的调优方案:

shmall:以字节为单位规定一次在该系统中可以使用的共享内存总量(单次申请的上限)

shmmax:以字节为单位规定每一个共享内存片段的最大大小

shmmni:规定系统范围内最大共享内存片段。在64和32位的系统上默认值都是4096

七.与容量相关的文件系统可调优参数:

file-max:列出内核分配的文件句柄的最大值

dirty_ratio:规定百分比值,当脏数据达到系统内存总数的这个百分比值后开始执行pdflush,默认为20

dirty_background_ratio:规定百分比值,当某一个进程自己所占用的脏页比例达到系统内存总数的这个百分比值后开始在后台执行pdflush,默认为10

dirty_expire_centisecs:pdlush每隔百分之一秒的时间开启起来刷新脏页,默认值为3000,所以每隔30秒起来开始刷新脏页

dirty_writeback_centisecs:每隔百分之一秒开始刷新单个脏页。默认值为500,所以一个脏页的存在时间达到了5秒,就开始刷新脏

八.linux内存常用的观察指标命令

Memory activity

vmstat [interval] [count]

sar -r [interval] [count]

Rate of change in memory

sar -R [interval] [count]

frmpg/s:每秒释放或者分配的内存页,如果为正数,则为释放的内存页;如果为负数,则为分配的内存页

bufpg/s:每秒buffer中获得或者释放的内存页。如果为正数则为获得的内存页,为负数。则为释放的内存页

campg/s:每秒cache中获得或者释放的内存页。如果为正数则为获得的内存页,为负数。则为释放的内存页

Swap activity

sar -W [interval] [count]

ALL IO

sar -B [interval] [count]

pgpgin/s:每秒从磁盘写入到内核的块数量

pgpgout/s:每秒从内核写入到磁盘的块数量

fault/s:每秒钟出现的缺页异常的个数

majflt/s:每秒钟出现的大页异常的个数

pgfree/s:每秒回收回来的页面个数

Ⅱ 关于linux系统下的物理内存映射

内存是一种存储设备,现在一般是ddr
sdram,地址是用来标记内存的数据的。在操作系统中物理内存指实际的ddr
sdram,而虚拟内存指的是在硬盘中的缓存,windows中是页面文件,linux中是swap分区。cpu产生的地址是虚拟地址也可以称作有效地址,而在cpu外地址线上的信号称作实际地址或物理地址。这2类地址有某种对应关系,由操作系统管理。如果是x86架构的话,物理地址和虚拟地址中间还有线性地址的概念。

Ⅲ Linux将设备地址映射到用户空间内存映射与VMA

一般情况下,用户空间是不可能也不应该直接访问设备的,但是,设备驱动程序中可实现mmap ()函数,这个函数可使得用户空间能直接访问设备的物理地址。实际上,mmap ()实现了这样的一个映射过程:它将用户空间的一段内存与设备内存关联,当用户访问用户空间的这段地址范围时,实际上会转化为对设备的访问。
这种能力对于显示适配器一类的设备非常有意义,如果用户空间可直接通过内存映射访问显存的话,屏幕帧的各点像素将不再需要一个从用户空间到内核空间的复制的过程。
mmap ()必须以PAGE_SIZE为单位进行映射,实际上,内存只能以页为单位进行映射,若要映射非PAGE_SIZE整数倍的地址范围,要先进行页对齐,强行以PAGE_SIZE的倍数大小进行映射。
从file_operations文件操作结构体可以看出,驱动中mmap ()函数的原型如下:
int ( *mmap)(struct file *, struct vm_area_struct* ) ;
驱动中的mmap () 函数将在用户进行mmap ()系统调用时最终被调用,mmap ()系统调用的原型与file_operations中mmap ()的原型区别很大,如下所示:
caddr_t mmap (caddr_t addr,size_t len,int prot,int flags,int fd,off_t offset);
参数fd为文件描述符,一般由open ()返回,fd也可以指定为-1,此时需指定flags参数中的MAP_ANON,表明进行的是匿名映射。
len是映射到调用用户空间的字节数,它从被映射文件开头offset个字节开始算起,offset参数一般设为0,表示从文件头开始映射。
prot参数指定访问权限,可取如下几个值的“或”:PROT_READ(可读)、PROT_WRITE(可写)、PROT_EXEC(可执行)和PROT_NONE(不可访问)。
参数addr指定文件应被映射到用户空间的起始地址,一般被指定为NULL,这样,选择起始地址的任务将由内核完成,而函数的返回值就是映射到用户空间的地址。其类型caddr_t实际上就是void*。
当用户调用mmap ())的时候,内核会进行如下处理。
1)在进程的虚拟空间查找一块VMA。
2)将这块VMA进行映射。
3)如果设备驱动程序或者文件系统的file_operations定义了mmap ()操作,则调用它。
4)将这个VMA插入进程的VMA链表中。
file_operations中mmap ()函数的第一个参数就是步骤1)找到的VMA。
由mmap ()系统调用映射的内存可由munmap ()解除映射,这个函数的原型如下:
int munmap(caddr_t addr, size_t len ) ;
驱动程序中mmap ()的实现机制是建立页表,并填充VMA结构体中vm_operations_struct指针。

Ⅳ LINUX内存映射问题

Linux的内存模型,一般为:

地址
作用
说明

>=0xc000 0000
内核虚拟存储器
用户代码不可见区域

<0xc000 0000
Stack(用户栈)
ESP指向栈顶





空闲内存

>=0x4000 0000
文件映射区

<0x4000 0000



空闲内存

Heap(运行时堆)
通过brk/sbrk系统调用扩大堆,向上增长。

.data、.bss(读写段)
从可执行文件中加载

>=0x0804 8000(0x00008000 for arm linux)
.init、.text、.rodata(只读段)
从可执行文件中加载

<0x0804 8000(0x00008000 for arm linux)
保留区域

运行一个测试程序,观察其结果:

#include <stdio.h>

int main(int argc, char* argv[])

{

int first = 0;

int* p0 = malloc(1024);

int* p1 = malloc(1024 * 1024);

int* p2 = malloc(512 * 1024 * 1024 );

int* p3 = malloc(1024 * 1024 * 1024 );

printf("main=%p print=%p\n", main, printf);

printf("first=%p\n", &first);

printf("p0=%p p1=%p p2=%p p3=%p\n", p0, p1, p2, p3);

getchar();

return 0;

}

运行后,输出结果为:

main=0x8048404 print=0x8048324

first=0xbfcd1264

p0=0x9253008 p1=0xb7ec0008 p2=0x97ebf008 p3=0x57ebe008

my pc (fc5)输出结果如下:

main=0x80483f4 print=0x8048324
first=0xbf848660
p0=0x9ab2008 p1=0xb7e38008 p2=0x97e37008 p3=(nil)

arm-linux输出如下结果:

main=0x8528 print=0x8404
first=0xbec9fe10
p0=0x11008 p1=0x4005a008 p2=(nil) p3=(nil)

main和print两个函数是代码段(.text)的,其地址符合表一的描述。

first是第一个临时变量,由于在first之前还有一些环境变量,它的值并非0xbfffffff,而是0xbfcd1264,这是正常的。

p0是在堆中分配的,其地址小于0x4000 0000,这也是正常的。

但p1和p2也是在堆中分配的,而其地址竟大于0x4000 0000,与表一描述不符。

原因在于:运行时堆的位置与内存管理算法相关,也就是与malloc的实现相关。关于内存管理算法的问题,我们在后继文章中有详细描述,这里只作简要说明。在glibc实现的内存管理算法中,Malloc小块内存是在小于0x4000 0000的内存中分配的,通过brk/sbrk不断向上扩展,而分配大块内存,malloc直接通过系统调用mmap实现,分配得到的地址在文件映射区,所以其地址大于0x4000 0000。

Ⅳ Linux I/O内存静态映射

Linux移植到目标电路板的过程中,有得会建立外设IO内存物理地址到虚拟地址的静态映射,这个映射通过在与电路板对应的map_desc结构体数组中添加新的成员来完成。iotable_init()是最终建立页映射的函数,它通过ACHINE_START、MACHINE_END宏赋值给电路板的map_io())函数。将Linux操作系统移植到特定平台上,MACHINE_START(或者DT_MACHINE_START)、MACHINE_END宏之间的定义针对特定电路板而设计,其中的map_io ()成员函数完成IO内存的静态映射。在一个已经移植好操作系统的内核中,驱动工程师可以对非常规内存区域的IO内存(外设控制器寄存器、MCU内部集成的外设控制器寄存器等)依照电路板的资源使用情况添加到map_desc数组中,但是目前该方法已经不值得推荐。
Cache和DMA本身似乎是两个毫不相关的事物。Cache被用作CPU针对内存的缓存,利用程序的空间局部性和时间局部性原理,达到较高的命中率,从而避免CPU每次都必须要与相对慢速的内存交互数据来提高数据的访问速率。DMA可以作为内存与外设之间传输数据的方式,在这种传输方式之下,数据并不需要经过CPU中转。
假设DMA针对内存的目的地址与Cache缓存的对象没有重叠区域,DMA和Cache之间将相安无事。但是,如果DMA的目的地址与Cache所缓存的内存地址访问有重叠,经过DMA操作,与Cache缓存对应的内存中的数据已经被修改,而CPU本身并不知道,它仍然认为Cache中的数据就是内存中的数据,那在以后访问Cache映射的内存时,它仍然使用陈旧的Cache数据。这样就会发生Cache与内存之间数据“不一致性”的错误。

Ⅵ Linux - 用户态内存映射 和 内核态内存映射

操作系统的内存管理,主要分为三个方面。
第一,物理内存的管理,相当于会议室管理员管理会议室。
第二,虚拟地址的管理,也即在项目组的视角,会议室的虚拟地址应该如何组织。
第三,虚拟地址和物理地址如何映射,也即会议室管理员如果管理映射表。

那么虚拟地址和物理地址如何映射呢?

每一个进程都有一个列表vm_area_struct,指向虚拟地址空间的不同的内存块,这个变量的名字叫mmap。

其实内存映射不仅仅是物理内存和虚拟内存之间的映射,还包括将文件中的内容映射到虚拟内存空间。这个时候,访问内存空间就能够访问到文件里面的数据。而仅有物理内存和虚拟内存的映射,是一种特殊情况。

如果我们要申请小块内存,就用brk。brk函数之前已经解析过了,这里就不多说了。如果申请一大块内存,就要用mmap。对于堆的申请来讲,mmap是映射内存空间到物理内存。

另外,如果一个进程想映射一个文件到自己的虚拟内存空间,也要通过mmap系统调用。这个时候mmap是映射内存空间到物理内存再到文件。可见mmap这个系统调用是核心,我们现在来看mmap这个系统调用。

用户态的内存映射机制包含以下几个部分。

物理内存根据NUMA架构分节点。每个节点里面再分区域。每个区域里面再分页。

物理页面通过伙伴系统进行分配。分配的物理页面要变成虚拟地址让上层可以访问,kswapd可以根据物理页面的使用情况对页面进行换入换出。

对于内存的分配需求,可能来自内核态,也可能来自用户态。

对于内核态,kmalloc在分配大内存的时候,以及vmalloc分配不连续物理页的时候,直接使用伙伴系统,分配后转换为虚拟地址,访问的时候需要通过内核页表进行映射。

对于kmem_cache以及kmalloc分配小内存,则使用slub分配器,将伙伴系统分配出来的大块内存切成一小块一小块进行分配。

kmem_cache和kmalloc的部分不会被换出,因为用这两个函数分配的内存多用于保持内核关键的数据结构。内核态中vmalloc分配的部分会被换出,因而当访问的时候,发现不在,就会调用do_page_fault。

对于用户态的内存分配,或者直接调用mmap系统调用分配,或者调用malloc。调用malloc的时候,如果分配小的内存,就用sys_brk系统调用;如果分配大的内存,还是用sys_mmap系统调用。正常情况下,用户态的内存都是可以换出的,因而一旦发现内存中不存在,就会调用do_page_fault。

Ⅶ Linux I/O内存静态映射

在将Linux移植到目标电路板的过程中,有得会建立外设IO内存物理地址到虚拟地址的静态映射,这个映射通过在与电路板对应的map_desc结构体数组中添加新的成员来完成。iotable_init()是最终建立页映射的函数,它通过ACHINE_START、MACHINE_END宏赋值给电路板的map_io())函数。将Linux操作系统移植到特定平台上,MACHINE_START(或者DT_MACHINE_START)、MACHINE_END宏之间的定义针对特定电路板而设计,其中的map_io ()成员函数完成IO内存的静态映射。在一个已经移植好操作系统的内核中,驱动工程师可以对非常规内存区域的IO内存(外设控制器寄存器、MCU内部集成的外设控制器寄存器等)依照电路板的资源使用情况添加到map_desc数组中,但是目前该方法已经不值得推荐。
Cache和DMA本身似乎是两个毫不相关的事物。Cache被用作CPU针对内存的缓存,利用程序的空间局部性和时间局部性原理,达到较高的命中率,从而避免CPU每次都必须要与相对慢速的内存交互数据来提高数据的访问速率。DMA可以作为内存与外设之间传输数据的方式,在这种传输方式之下,数据并不需要经过CPU中转。
假设DMA针对内存的目的地址与Cache缓存的对象没有重叠区域,DMA和Cache之间将相安无事。但是,如果DMA的目的地址与Cache所缓存的内存地址访问有重叠,经过DMA操作,与Cache缓存对应的内存中的数据已经被修改,而CPU本身并不知道,它仍然认为Cache中的数据就是内存中的数据,那在以后访问Cache映射的内存时,它仍然使用陈旧的Cache数据。这样就会发生Cache与内存之间数据“不一致性”的错误。

阅读全文

与linux内存映射查看相关的资料

热点内容
法国阿尔法公司电影有哪些 浏览:669
工商银行app哪里能体现出名字 浏览:885
如何把手机app添加到车载 浏览:648
十部经典篮球教练小说 浏览:193
最美壁纸安卓叫什么 浏览:477
达虎电影网最新官网 浏览:878
python就业形势 浏览:434
自制解压游戏手工 浏览:498
m1代码编译 浏览:679
华为怎么安装安卓app 浏览:553
福昕阅读器打印pdf 浏览:788
python中mean函数 浏览:405
《消失的眼角膜》简介 浏览:421
男主是纳粹军官,弟弟是苏联 浏览:800
韩国小电影网站 浏览:936
有没有没有赌场广告的影视网 浏览:125
51单片机测量电容 浏览:154
有床戏的爱情电影 浏览:374
大陆激情大尺度露点电影 浏览:652
欢乐斗地主比例算法 浏览:871