首页 > 作文

物理内存是什么

更新时间:2023-03-05 23:47:18 阅读: 评论:0

高空跳水-家庭演播室

物理内存是什么
2023年3月5日发(作者:英文生日祝福语)

大块物理地址连续的内存分配

@

Jun1,2009

目录目录

目录

1前言2

2kernel内存的分配2

2.1kmalloc......................................2

2.2vmalloc......................................2

2.3alloc_page类函数.................................2

3实际解决方案3

3.1预留内存(mem=).................................3

3.2bigphysarea....................................5

3.2.1bigphysarea简介.............................5

3.2.2实现原理.................................5

1

2KERNEL内存的分配

1前言

工作中,我们经常能够遇到一些对内存有特殊要求的硬件,有些是其本身的设计

要求所至,而另一些则是从系统性能考虑(如不能支持Scatter/gatherDMA),两种情况

下都必须为其driver分配大块的物理地址连续内存块。更槽糕的是,系统连续运行时间

越长,大块物理地址连续的内存块分配到的可能性就越低。大多数情况下(内存泄露除

外),你会发现系统的剩余内存(free或cat/proc/meminfo)足够大却依然无法分配到,

很显然,内存碎片(memoryfragmentation)出现了。在uClinux系统中,由于没有VM的

存在,问题更加突出。当你播放一个H.264或者WMVHD(1920x1080p)的视频时,甚

至播放一个WMAPro,系统都有可能“Outofmemory",根本原因还是系统此时无法为

videodecode或audiodecoder分配一个大块的物理地址连续内存。

2kernel内存的分配

那么如何才能保证一定能够分配到大块物理地址连续的内存呢?在看下面的解决方

案之前,我们有必要了解一下Linuxkernel中常用的几种内存分配方式,从能分配的上

限和分到的可能性来看是否能够满足需求。

2.1kmalloc

kmalloc是建立在slab分配器之上,它并不直接从buddysystem中获得空闲页面,

而是从slab页面分配器获得需要的内存。kmalloc主要用于分配以字节大小为单位

的小内存区域(32131072),所以kmalloc能够分配的内存块的大小有一个上限。slab

的实现限制了最大分配的大小为128k,即131072bytes,理论上可以更改slab.c中的

cache_sizes数组中的最大值使得kmalloc可以获得更大的内存数,但是有必要这么做

么?因为128k对于slab而言是一个很合理的经验值,而且获取较大内存的方法有很

多,我们不需要为了解决一个问题而引入一系列问题。

kmalloc分配的内存在线形地址和物理地址上都是连续的,但是它不能分配到高端

内存区域(Highmemory)内的内存,高端内存区域内的内存必须由专门的方式(kmap)来

获得。而且系统长时间运行后,也并不能保证能够分配到大块内存。

2.2vmalloc

vmalloc与kmalloc不同的是,vmalloc分配的内存只是在线形地址上是连续的,它

不保证分配的内存在物理上也连续。vmalloc的主要目的是用于非连续物理内存分配。

采用vmalloc的主要原因在于:由于buddysystem会产生外碎片(externalfragmentation)

,系统长时间运行后我们很难找到大块的物理连续的内存块,因此Linux采用vmalloc

来解决这个问题。由于vmalloc会涉及到页表的更改,并且以后访问用vmalloc申请的

内存,很有可能导致TLBmiss,效率肯定会损失一些。对于一定要使用大块物理连续

地址内存块的硬件来说,vmalloc显然不行。uClinux中,由于没有物理地址和虚拟地

址的区别,vmalloc就等同于kmalloc.

2.3alloc_page类函数

此类函数主要通过buddysystem进行分配,是以页为单位分配大块连续内存的.但

是一次请求能分配的最大物理页数由变量MAX_ORDER决定.

1staticinlinestructpage

*

2alloc_pages(unsignedintgfp_mask,unsignedintorder)

3{

2

3实际解决方案

4if(unlikely(order>=MAX_ORDER))

5returnNULL;

6

7returnalloc_pages_current(gfp_mask,order);

8}

Linux中(linux-2.6.11/include/linux/mmzone.h)

1/

*

Freememorymanagement-zonedbuddyallocator.

*

/

2#ifndefCONFIG_FORCE_MAX_ZONEORDER

3#defineMAX_ORDER11

4#el

5#defineMAX_ORDERCONFIG_FORCE_MAX_ZONEORDER

6#endif

最大为2048个page,8M的内存。

而在uClinux中(linux-2.4.22-uc0/include/linux/mmzone.h)

1#ifdefCONFIG_FORCE_MAX_ZONEORDER

2#defineMAX_ORDERCONFIG_FORCE_MAX_ZONEORDER

3#elifdefined(CONFIG_NO_MMU_LARGE_ALLOCS)

4#defineMAX_ORDER13

5#el

6#defineMAX_ORDER10

7#endif

即便在定义了CONFIG_NO_MMU_LARGE_ALLOCS的情况下,最多也只能分配32M.

由上可见,alloc_page或kmalloc都有分配上限,而且也无法确保系统长时间运行

后依然能够分配到大块物理连续的内存块。系统由于长时间运行后,大块连续物理内存

被系统中持续不断的小块内存分配请求打散,找成内存碎片。一个可行的解决方法就

是,把小内存请求和大块内存请求隔离开,即:分出一大块内存独立管理,用来满足所

有的大块内存请求;剩余内存由系统直接管理,满足小内存请求和系统任务分配需要。

问题是:如何从内存中分配大块的内存呢(从128M中分出80M)?

3实际解决方案

3.1预留内存(mem=)

系统启动时,可以通过mem=(kernelparameter,可在commandline指定mem=XXX

)或类似机制直接指定由系统直接管理的内存数,剩余内存由driver独立管理。用户

进程要想访问预留的存储器,首先必须用打开驱动程序提供的设备文件,然后利用

mmap()映射内存。而驱动程序一侧则必须实现ioremap.以我们的系统为例,系统配置

为:

•OS:uClinux2.4.22-uc0,

•CPU:PT110(PicoTurb生产,ARM7TDMI兼容),

•DRAM:128M

•Flash:16M

3

3.1预留内存(mem=)3实际解决方案

当config中的DRAM_SIZE设为0x03000000时(等同于mem=48M),48MB将由内

核管理,OS下运行的各种任务和小内存分配请求共享此块内存。剩下的80M,OS无

法管理,由驱动程序独立管理。

kernelconfig设置:

DRAM_BASE=0x90080000

DRAM_SIZE=0x03000000

FLASH_MEM_BASE=0x46000000

FLASH_SIZE=0x00800000

CONFIG_16MB_FLASH=y

0x00020000

Hostinterface

0x00030000

0x00040000

0x00050000

DRMCRTL0

DRMCRTL1

DRMCRTL2

CPUBlock

0x00060000

0x40000000

configuration

0x44000000

0x45000000

0x46000000

MEMORY_BASE_HOST_SFLASH

MEMORY_BASE_HOST_PB0

MEMORY_BASE_HOST_PB1

MEMORY_BASE_HOST_PB2

CONFIG

0x47000000

Hostmemory

ROOTFS

ROOTFS2

Cert

Flag

Bootloader

0x46020000

0x46040000

0x46bc0000

0x46fc0000

0x46fe0000

PCI_BASE_CONFIG

PCI_BASE_IO

PCI_BASE_MEMORY

0x50000000

0x58000000

0x60000000

FLASH

0x90000000

CACHE_START

BOOTLOADER

CACHE_START

DRAM_BASE

CACHE_START

KERNEL

CACHE_START

MEM_END

CACHE_START

RESERVE_END

CACHE_START

MEMORY_BASE_DRAMCRL1

0x90060000

0x90080000

0x90090000

0x93080000

0x98080000

0xa0000000

0xb0000000

MEMORY_BASE_DRAMCRL2

NON-CACHE

CACHE

0xFFFFFFFF

0x80000000

CACHE_START

0x00000000

图1:系统内存映射(memorymap)

系统内存:MEM_END=DRAM_BASE+DRAM_SIZE=0x90080000+0x03000000

=0x93080000=0x13080000|0x80000000.

4

3.2bigphysarea3实际解决方案

预留内存:0x90080000+0x08000000=0x98080000.

RESERVE_END也可以由driver验证:

cat/proc/driver/xxxx/0/resources

#*

[MM0]

*

MemoryArea[0x13080000,83361792(79.5MB)]

***

奇怪的是:0x93080000却变成了0x13080000。其实从0-0x7FFFFFFF(2G空间)和0x80000000

-0xFFFFFFFF(2G空间)对应的是同一地址空间,区别只是前2G为Non-Cache地址,

后2G为Cache地址。

1#defineXXXX_DRAM_C2NC(x)((x)&0x7fffffff)

2#defineXXXX_DRAM_NC2C(x)((x)|0x80000000)

这种做法(mem=)有其明显的缺陷,试想,在一个拥有4GB的x86机器上,mem=3G

会为driver预留最后的1GB,不幸的是,当driver读写这1GB时,有可能直接写到PCI

configspace中去了,产生奇怪的错误也就不难理解了。从理论上来讲,用"mem="为

driver预留内存是一个错误的做法,它只是碰巧在我们的平台工作而已,而且也为其他

系统的移植埋下了定时炸弹.它并不能在内存非连续或有hotplug内存的系统上很好地工

作.

对于本例中的嵌入式应用,该方法还是可以接受的。那么什么是正解呢?这就是下

面要提到的bigphysarea.

3.2bigphysarea

3.2.1bigphysarea简介

bigphysareapatch是基于bootmem的分配大块(比kmalloc,alloc_page上限大)物理

地址连续的内存块的方法。预留的内存由bigphysarea独立管理,同时还提供了2个接口

给其它需要大块物理地址连续内存块的driver使用:

•分配内存

1caddr_tbigphysarea_alloc_pages(intcount,intalign,int

priority)

count为所分页数,align为地址对其系数:PAGE_SIZE*align,priority同kmalloc

中的参数意义一样,可以为GFP_ATOMIC(用于中断环境),GFP_KERNEL(usual

calls).返回值为所分区域的基地址。

•释放内存

1voidbigphysarea_free_pages(caddr_tba)

ba为bigphysarea_alloc_pages返回值

3.2.2实现原理

1static

2int__initbigphysarea_tup(char

*

str)

3{

4intpar;

5if(get_option(&str,&par)){

5

3.2bigphysarea3实际解决方案

6bigphysarea_pages=par;

7//Allocthememory

8bigphysarea=alloc_bootmem_low_pages(

bigphysarea_pages<

9if(!bigphysarea){

10printk(KERN_CRIT"bigphysarea:not

enoughmemoryfor%dpagesn",

bigphysarea_pages);

11return-ENOMEM;

12}

13

14//registertheresourceforit

15mem_=bigphysarea;

16mem_=mem_+(

bigphysarea_pages<

17request_resource(&iomem_resource,&

mem_resource);

18}

19return1;

20}

1__tup("bigphysarea=",bigphysarea_tup);

这里提到了m要解决的问题就是如何初始化buddy,而初始化

buddy很显然需要分配内存给buddy数据结构,那么由谁分配而且如何分配内存呢?这

就是bootmem的职责所在。简而言之:

•bootmem

使

用就是系统启动时,帮助buddy等内存分配系统完成初始化,同时用bitmap标记

buddy等数据结构使用的页面(不能释放的页面),然后把所有未使用的内存页(也

包括bootmembitmap等数据结构所使用的内存页)释放给buddy。

•bootmem只在buddy尚未接管内存管理时使用,在buddy等内存分配系统初始化

完成后将废弃不用。

•bootmem基本思想是用bitmap标记内存页,分配方法是从低往高找直到找到

一块或连续多块满足大小要求的空闲页面为止。(详见[5,Chapter5,BootMemory

allocator])

bigphysarea根据kernelcommadline(bigphysarea=page数)传入的预留的page数,调

用alloc_bootmem_low_pages分配预留的内存.

需要大块物理连续内存块的driver可以调用bigphysarea_alloc_pages从bigphysarea

driver分配内存,bigphysarea_alloc_pages实现如下:

1typedefstructrange_struct{

2structrange_struct

*

next;

3caddr_tba;/

*

baofallocated

block

*

/

4size_tsize;/

*

sizeinbytes

*

/

5}range_t;

6

7/

*

8*

0:nothinginitialized

9*

1:bigphysarea_pagesinitialized

10*

2:freelistinitialized

6

3.2bigphysarea3实际解决方案

11*

/

12staticintinit_level=0;

13staticintbigphysarea_pages=0;

14staticcaddr_tbigphysarea=0;

15staticrange_t

*

free_list=NULL;

16staticrange_t

*

ud_list=NULL;

17staticstructresourcemem_resource={"Bigphysarea",0,0,

IORESOURCE_MEM|IORESOURCE_BUSY};

18

19/

*

20*

Allocate`count'

arealignedto

21*

amultipleof`align'.`priority'hasthesamemeaningin

kmalloc,it

22*

isneededformanagementinformation.

23*

Thisfunctionmaynotbecalledfromaninterrupt!

24*

/

25caddr_tbigphysarea_alloc_pages(intcount,intalign,int

priority)

26{

27range_t

*

range,

**

range_ptr,

*

new_range,

*

align_range;

28caddr_taligned_ba;

29

30if(init_level<2)

31if(init2(priority))

32return0;

33new_range=NULL;

34align_range=NULL;

35

36if(align==0)

37align=PAGE_SIZE;

38el

39align=align

*

PAGE_SIZE;

40/

*

41*

Searchafreeblockwhichislargeenough,even

withalignment.

42*

/

43range_ptr=&free_list;

44while(

*

range_ptr!=NULL){

45range=

*

range_ptr;

46aligned_ba=

47(caddr_t)((((unsignedlong)range->ba+

align-1)/align)

*

align);

48if(aligned_ba+count

*

PAGE_SIZE<=

49range->ba+range->size)

50break;

51range_ptr=&range->next;

52}

53if(

*

range_ptr==NULL)

54return0;

55range=

*

range_ptr;

56/

*

57*

Whenwehavetoalign,thepagesneededfor

alignmentcan

58*

beputbacktothefreepool.

59*

Wecheckhereifweneedacondrangedata

structurelater

7

3.2bigphysarea3实际解决方案

60*

andallocateitnow,sothatwedon'thavetocheck

fora

61*

failedkmalloclater.

62*

/

63if(aligned_ba-range->ba+count

*

PAGE_SIZE<

range->size){

64new_range=kmalloc(sizeof(range_t),priority)

;

65if(new_range==NULL)

66returnNULL;

67}

68if(aligned_ba!=range->ba){

69align_range=kmalloc(sizeof(range_t),

priority);

70if(align_range==NULL){

71if(new_range!=NULL)

72kfree(new_range);

73returnNULL;

74}

75align_range->ba=range->ba;

76align_range->size=aligned_ba-range->ba

;

77range->ba=aligned_ba;

78range->size-=align_range->size;

79align_range->next=range;

80*

range_ptr=align_range;

81range_ptr=&align_range->next;

82}

83if(new_range!=NULL){

84/

*

85*

Rangeislargerthanneeded,createanew

listelementfor

86*

theudlistandshrinktheelementinthe

freelist.

87*

/

88new_range->ba=range->ba;

89new_range->size=count

*

PAGE_SIZE;

90range->ba=new_range->ba+new_range->

size;

91range->size=range->size-new_range->size;

92}el{

93/

*

94*

Rangefitsperfectly,removeitfromfree

list.

95*

/

96*

range_ptr=range->next;

97new_range=range;

98}

99/

*

100*

Inrtblockintoudlist

101*

/

102new_range->next=ud_list;

103ud_list=new_range;

104

105returnnew_range->ba;

106}

8

3.2bigphysarea3实际解决方案

Bigphysarea为已使用内存(ud)和空闲(free)内存各维护一个链表,分配时从free

链表中寻找一个符合对齐和大小要求的block,当然最初的free表只有一个block.

1static

2intinit2(intpriority)

3{

4if(init_level==1){

5free_list=kmalloc(sizeof(range_t),priority)

;

6if(free_list!=NULL){

7free_list->next=NULL;

8free_list->ba=bigphysarea;

9free_list->size=bigphysarea_pages

*

PAGE_SIZE;

10init_level=2;

11return0;

12}

13}

14return

15}

当调用bigphysarea_free_pages释放内存时,首先从ud链表中删除对应的项,然

后在free链表中查找合适的插入点并尽可能合并相邻项。

1/

*

2*

Freepagesallocatedwith`bigphysarea_alloc_pages'.`ba'

mustbean

3*

addressreturnedby`bigphysarea_alloc_pages'.

4*

Thisfunctionmynotbecalledfromaninterrupt!

5*

/

6voidbigphysarea_free_pages(caddr_tba)

7{

8range_t

*

prev,

*

next,

*

range,

**

range_ptr;

9

10/

*

11*

Searchtheblockintheudlist.

12*

/

13for(range_ptr=&ud_list;

14*

range_ptr!=NULL;

15range_ptr=&(

*

range_ptr)->next)

16if((

*

range_ptr)->ba==ba)

17break;

18if(

*

range_ptr==NULL){

19printk("bigphysarea_free_pages(0x%08x),not

allocated!n",

20(unsigned)ba);

21return;

22}

23range=

*

range_ptr;

24/

*

25*

Removerangefromtheudlist:

26*

/

27*

range_ptr=(

*

range_ptr)->next;

28/

*

29*

Thefree-listissortedbyaddress,arch

inrtionpoint

30*

andinrtblockinfreelist.

31*

/

9

参考文献参考文献

32for(range_ptr=&free_list,prev=NULL;

33*

range_ptr!=NULL;

34prev=

*

range_ptr,range_ptr=&(

*

range_ptr)->

next)

35if((

*

range_ptr)->ba>=ba)

36break;

37range->next=

*

range_ptr;

38*

range_ptr=range;

39/

*

40*

Concatenatefreerangewithneighbors,ifpossible.

41*

Tryforupperneighbor(nextinlist)first,then

42*

forlowerneighbor(predecessorinlist).

43*

/

44if(range->next!=NULL&&

45range->ba+range->size==range->next->ba){

46next=range->next;

47range->size+=range->next->size;

48range->next=next->next;

49kfree(next);

50}

51if(prev!=NULL&&

52prev->ba+prev->size==range->ba){

53prev->size+=prev->next->size;

54prev->next=range->next;

55kfree(range);

56}

57}

作为一个很有用的内存分配patch,bigphysarea却并没有merge到kernelmainline

中去,主要原因就是:几乎没有什么driver能够用到bigphysarea.

注:本例中用到的bigphysareapatch版本为.

参考文献

[1]Whatisbigphysarea,/Q/What_is_bigphysarea

[2]Whynobigphysareainmainline?/pipermail/linuxppc64-dev/2005-

March/

[3]/pipermail/celinux-dev/2007-September/

[4]/middelink/En/#bigphysarea

[5]UnderstandingtheLinuxVirtualMemoryManagement,MelGorman,PrenticeHall,2004

10

本文发布于:2023-03-05 23:47:17,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/1678031238151019.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:物理内存是什么.doc

本文 PDF 下载地址:物理内存是什么.pdf

相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 站长QQ:55-9-10-26 专利检索|