关于Linux内存管理goodWord文档格式.docx

上传人:b****6 文档编号:21824525 上传时间:2023-02-01 格式:DOCX 页数:22 大小:26.25KB
下载 相关 举报
关于Linux内存管理goodWord文档格式.docx_第1页
第1页 / 共22页
关于Linux内存管理goodWord文档格式.docx_第2页
第2页 / 共22页
关于Linux内存管理goodWord文档格式.docx_第3页
第3页 / 共22页
关于Linux内存管理goodWord文档格式.docx_第4页
第4页 / 共22页
关于Linux内存管理goodWord文档格式.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

关于Linux内存管理goodWord文档格式.docx

《关于Linux内存管理goodWord文档格式.docx》由会员分享,可在线阅读,更多相关《关于Linux内存管理goodWord文档格式.docx(22页珍藏版)》请在冰豆网上搜索。

关于Linux内存管理goodWord文档格式.docx

char*p2;

//p2为局部变量,所以存储于栈区

char*p3="

123456"

//123456\0在常量区(已初始化数据区),p3在栈上。

staticintc=0;

//c存储于静态数据区(静态数据区和全局初始化区同在一个区域)

p1=(char*)malloc(10);

//系统动态分配得来的10和20字节的区域就在堆区

p2=(char*)malloc(20);

free(p1);

free(p2);

return0;

}

2、内存的分配(内存的申请)

1)申请方式

Stack(静态分配):

静态对象是有名字的变量,可以直接对其进行操作。

由系统自动分配内存。

例如,声明在函数中一个局部变量intb;

系统自动在栈中为b开辟空间。

Heap(动态分配):

动态对象是没有名字的变量,需要通过指针间接地对它进行操作。

需要程序员自己申请内存,并指明大小。

在C中malloc函数,如p1=(char*)malloc(10);

在C++中用new运算符,如p2=newchar[20];

//(char*)malloc(20);

分配堆空间之后,p1、p2得到所分配堆空间首地址,将会指向堆空间。

2)申请后系统的响应

栈:

只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出

堆:

首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

其次,大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。

此外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

3)申请大小的限制

栈:

在Windows下,栈是高地址向低地址扩展的数据结构,是一块连续的内存的区域。

这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的。

在WINDOWS下,栈的大小是2M(也有的说是1M,总之它是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。

因此,能从栈获得的空间较小。

堆:

堆是低地址向高地址扩展的数据结构,是不连续的内存区域。

这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。

堆的大小受限于计算机系统中有效的虚拟内存,由此可见,堆获得的空间很灵活。

但由程序员操作的过程中容易发生内存泄露,也极易产生内存空间的不连续,即内存碎片(频繁使用malloc和free(new和delete)的结果)。

4)申请效率的比较

栈由系统自动分配,速度较快,但程序员是无法控制的。

堆是由malloc或者new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

5)分配效率的比较

栈是机器提供的数据结构,机器会在底层对栈提供支持:

分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令。

堆则是C函数库提供的,它的机制很复杂。

可见,堆得存取效率和栈比较起来要低得多。

3、下面再给出一个数据存储区域的实例

#include<

stdio.h>

malloc.h>

unistd.h>

alloca.h>

externvoidafunc(void);

//声明afunc()函数

externetext,edata,end;

//声明三个外部变量

intbss_var;

//未初始化全局数据存储在BSS区

intdata_var=42;

//初始化全局数据存储在数据区

//定义了一个宏,用于打印地址

#defineSHW_ADR(ID,I)printf("

the%8s\tisatadr:

%8x\n"

ID,&

I);

intmain(intargc,char*argv[])

char*p,*b,*nb;

printf("

Adretext:

%8x\tAdredata%8x\tAdrend%8x\t\n"

&

etext,&

edata,&

end);

\ntextLocation:

\n"

);

SHW_ADR("

main"

main);

//查看代码段main函数位置

afunc"

afunc);

//查看代码段afunc函数位置

\NBSSLocation:

bss_var"

bss_var);

//查看BSS段变量位置

\NDATALocation:

data_var"

data_var);

//查看数据段变量位置

\nSTACKLocation:

afunc();

p=(char*)alloca(32);

//从栈中分配空间

if(p!

=NULL){

start"

p);

//打印栈空间的起始位置

end"

p+31);

//打印栈空间的结束位置

}

b=(char*)malloc(32*sizeof(char));

//从堆中分配空间

nb=(char*)malloc(16*sizeof(char));

//从堆中分配空间

\NHEAPLocation:

theheapstart:

%p\n"

b);

//打印堆起始位置

theheapend:

(nb+16*sizeof(char)));

//打印堆结束位置

\nbandnbinStack\n"

b"

//打印栈中字符指针变量b的存储位置

nb"

nb);

//打印栈中字符指针变量nb的存储位置

free(b);

//释放申请的堆空间

free(nb);

voidafunc(void)

staticintlonglevel=0;

//静态数据存储在数据段中

intstack_var;

//局部变量,存储在栈区

if(++level==5)

{return;

stack_varisat:

%p\n"

stack_var);

//打印局部变量的地址

//递归执行afunc函数

4、介绍几个内存管理函数

1)Malloc/free函数

原型:

externvoid*malloc(size_tnum_bytes);

 

头文件:

include<

stdlib.h>

功能:

分配长度为num_bytes字节的内存块  

返回值:

如果分配成功则返回指向被分配内存首地址的指针,否则返回空指针NULL。

说明:

该函数返回为void型指针,因此必要时要进行类型转换。

  

当内存不再使用时,应使用free()函数将内存块释放。

为什么不再使用时,要用free()释放掉所申请的内存?

由于内存区域总是有限的,不能无限制地分配下去。

程序应该尽可能地去节省资源,当申请的堆空间不再使用时,应该释放掉,交由其它进程来使用。

注意:

不能用free()来释放非malloc(),calloc(),realloc()函数所创建的堆空间,否则会发生错误。

2)new/delete(在C++中)

使用new/delete运算符实现内存管理比malloc/free函数更有优越性。

它们的定义如下:

Staticvoid*operatornew(size_tsz);

Staticvoid*operatordelete(void*p);

先看一段C++代码:

voidtest(void)

//申请一个sizeof(obj)大小的一块动态内存,并把头指针赋值给obj类型的指针变量a

obj*a=newobj;

deletea;

//清除并且释放所申请的内存

下面通过一段代码具体介绍一下new/delete的用法:

ClassA

Public:

A(){count<

<

“Aishere!

”<

endl;

}//构造函数

~A(){count<

}//析构函数

Private:

IntI;

};

A*pA=newA;

//调用new运算符申请空间

deletepA;

//删除pA

其中,语句newA完成了一下两个功能:

A.调用new运算符,在堆上分配一个sizeof(A)大小的内存空间。

B.调用构造函数A(),在所分配的内存空间上初始化对象。

语句deletepA完成的是相反的两件事:

A.调用析构函数~A(),销毁对象。

B.调用运算符delete,释放内存。

使用new比使用malloc()有以下优点:

A.New自动计算要分配给对象的内存空间大小,不使用sizeof运算符,这样一来简单,而来可以避免错误。

B.自动地返回正确的指针类型,不用进行强制类型转换。

C.用构造函数给分配的对象进行初始化。

使用malloc函数和new分配内存的时候,本身并没有对这块内存空间做清零等任何工作。

因此,申请内存空间后,其返回的新分配的空间是没有用零填充的,程序员须使用memset()函数来初始化内存。

3)realloc函数(更改已经配置的内存空间)

函数定义:

void*realloc(void*ptr,size_tsize)

参数ptr为先前由malloc、calloc和realloc所返回的内存指针,而参数size为新配置的内存大小。

realloc函数用来从堆上分配内存,当需要扩大一块内存空间时,realloc()试图直接从堆上当前内存段后面的字节中获得更多的内存空间:

如果能够分配成功,则返回指向这块新内存空间的首地址,而将原来的指针(realloc函数的参数指针)指向的空间释放掉;

如果当前内存段后面的空闲字节不够,那么就使用堆上第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,而将原来的数据块释放掉;

如果内存不足,重新申请空间失败,则返回NULL,此时原来的指针(realloc函数的参数指针)仍有效。

intmain(intargc,char*argv[],char*envp[])//主函数

intinput;

intn;

int*numbers1;

int*numbers2;

numbers1=NULL;

if((numbers2=(int*)malloc(5*sizeof(int)))==NULL)//numbers2指针申请空间

printf("

mallocmemoryunsuccessful"

//free(numbers2);

//numbers2=NULL;

exit

(1);

for(n=0;

n<

5;

n++)//初始化(0-4)

{

*(numbers2+n)=n;

numbers2'

sdata:

%d\n"

*(numbers2+n));

//把0-4打印出来

Enteranintegervalueyouwanttoremalloc(enter0tostop)\n"

//新申请空间大小 

scanf("

%d"

input);

numbers1=(int*)realloc(numbers2,(input+5)*sizeof(int));

//重新申请空间

if(numbers1==NULL)

Error(re)allocatingmemory"

exit

(1);

for(n=0;

n<

n++)//这5个数是从numbers2(原指针空间)拷贝而来

thenumbers1s'

sdatacopyfromnumbers2:

*(numbers1+n));

input;

n++)//新数据初始化(0-input)

*(numbers1+5+n)=n*2;

printf("

nummber1'

snewdata:

*(numbers1+5+n));

//numbers1++;

free(numbers1);

//释放numbers1

//free(numbers2);

//不能再释放numbers2,因为number2早已被系统自动释放

return0;

前面我们已经分析了linux如何利用伙伴系统,slab分配器分配内存,用这些方法得到的内存在物理地址上都是连续的,然而,有些时候,每次请求内存时,系统都分配物理地址连续的内存块是不合适的,可以利用小块内存“连接”成大块可使用的内存.这在操作系统设计中也被称为“内存拼接”,显然,内存拼接在需要较大内存,而内存访问相比之下不是很频繁的情况下是比较有效的.

  在linux内核中用来管理内存拼接的接口是vmalloc/vfree.用vmalloc分配得到的内存在线性地址是平滑的,但是物理地址上是非连续的.

  一:

准备知识:

  Linux用vm_struct结构来表示vmalloc使用的线性地址.vmalloc所使用的线性地址区间为:

VMALLOC_STARTVMALLOC_END.借用<

Understanding.the.Linux.Kernel.3rd>

>

中的一副插图,如下示:

  从上图中我们可以看到每一个vmalloc_area用4KB隔开,这样做是为了很容易就能捕捉到越界访问,因为中间是一个“空洞”.

  二:

相关的数据结构

  下面来分析一下vmallocarea的数据结构:

  structvm_struct{

  void*addr;

//虚拟地址

  unsignedlongsize;

//vm的大小

  unsignedlongflags;

//vm的标志

  structpage**pages;

//vm所映射的page

  unsignedintnr_pages;

//page个数

  unsignedlongphys_addr;

//对应的起始物理地址

  structvm_struct*next;

//下一个vm.用来形成链表

  }

  全局变量vmlist用来管理vm构成的链表

  全局变量vmlist用于访问vmlist所使用的信号量

  对于vm_struct有两个常用的操作:

get_vm_area/remove_vm_area

  get_vm_area:

用来分配一个合适大小的vm结构,分配成功之后,将其链入到vmlist中,代码在mm/vmalloc.c中.如下示:

  //size为vm的大小

  structvm_struct*get_vm_area(unsignedlongsize,unsignedlongflags)

  {

  //在VMALLOC_START与VMALLOC_END找到一段合适的空间

  return__get_vm_area(size,flags,VMALLOC_START,VMALLOC_END);

  //参数说明:

  //start:

起始地址end:

结束地址size空间大小

  structvm_struct*__get_vm_area(unsignedlongsize,unsignedlongflags,

  unsignedlongstart,unsignedlongend)

  structvm_struct**p,*tmp,*area;

  unsignedlongalign=1;

  unsignedlongaddr;

  //如果指定了VM_IOREMAP.则调整对齐因子

  if(flags&

VM_IOREMAP){

  intbit=fls(size);

  if(bit>

IOREMAP_MAX_ORDER)

  bit=IOREMAP_MAX_ORDER;

  elseif(bit<

PAGE_SHIFT)

  bit=PAGE_SHIFT;

  align=1ul<

bit;

  //将起始地址按照对齐因子对齐

  addr=ALIGN(start,align);

  //分配一个vm_struct结构空间

  area=kmalloc(sizeof(*area),GFP_KERNEL);

  if(unlikely(!

area))

  returnNULL;

  //PAGE_SIZE:

在i32中为4KB,即上面所说的间隔空洞

  size+=PAGE_SIZE;

size)){

  kfree(area);

  write_lock(&

vmlist_lock);

  //遍历vmlist:

找到合适大小的末使用空间

  for(p=&

vmlist;

(tmp=*p)!

=NULL;

p=&

tmp->

next){

  //若起始地址落在某一个vm区间,则调整起始地址为vm区间的末尾

  if((unsignedlong)tmp->

addr<

addr){

  if((unsignedlong)tmp->

addr+tmp->

size>

=addr)

  addr=ALIGN(tmp->

size+

  (unsignedlong)tmp->

addr,align);

  continue;

  //size+addr<

addr?

除非size==0

  if((size+addr)<

addr)

  gotoout;

  //中间的空隙可以容纳下size大小的vm.说明已经找到了这样的一个vm

  if(size+addr<

=(unsignedlong)tmp->

addr)

  gotofound;

  //调整起始地址为vm的结束地址

size+(unsignedlong)tmp->

  //如果超出了范围

  if(addr>

end-size)

  found:

  //找到了合适大小的空间,将area->

addr赋值为addr,然后链入vmlist中

  area->

next=*p;

  *p=area;

flags=flags;

addr=(void*)addr;

size=size;

pages=NULL;

nr_pages=0;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 思想汇报心得体会

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1