第八课.指针(三)

C++程序存储区域划分

首先了解两个数据结构:栈和队列,栈的特点是先进后出,队列的特点是先进先出;

在C++中,变量和函数通常存储在栈内,比如有以下程序:

int a=0;	//GVAR 全局初始化区
int* p1;	//bss 全局未初始化区

int main()	//text 代码区
{
	int b;	//stack 栈区变量
	char s[]="abc";	//stack 栈区变量
	int* p2=NULL;	//stack 栈区变量
	char* p3="123456";	//123456\0在常量区, p3在stack 栈区
	static int c=0;	//GVAR 全局初始化区
	p1=new int(10);	//heap 堆区变量
	p2=new int(20);	//heap 堆区变量

	return 0;	//text 代码区
}

顺序观察变量的地址:

&b  0x00aff968
s   0x00aff95c	// 数组名也是地址
&p2 0x00aff950 

可见,顺序越靠前的变量地址值越高,这是因为变量被逐个存入栈中,数据越靠近栈底,地址值越高;栈区域允许改变对象的值,在常量区的对象不允许改变值;

注意到在main函数外存在变量a,p1,变量a,p1不在栈区域,处在全局变量区域;在函数外或者类外定义的变量被称为全局变量(全局变量体现了其在函数内部或者类内部也可以看到它);根据其是否进行了初始化,变量会被细分到初始化区GVAR和未初始化区bss;

在函数内使用static定义变量时,该变量不会在栈区域分配,而是在全局变量区分配;

执行p1=new int(10)p2=new int(20)后,变量p1,p2的值为:

p1 0x00f6c160
p2 0x00f6c190

在程序中,new int(10)new int(20)先执行,其地址不像栈的分布,p1的值小于p2,这是因为关键词new意味着在堆区域分配内存;

形象地,代码和数据的存储如下:
fig1

  • 栈空间的资源分配和回收由系统自动完成,堆空间的资源分配和回收可以通过开发人员完成(new 和delete);
  • 对于BSS未初始化区,一般会默认设为0值;
  • 实际上图中少了一个区域,在堆空间和BSS区域中间还存在一个常量区;
  • TEXT代码区用于存放程序除了数据以外的逻辑

C++动态分配和回收原则

动态分配资源来自heap(堆),在堆上分配内存时,常用new关键字,与new相对应的是delete;动态分配内存会带来不确定性,在实时性要求较高的场合,最好不要用动态分配,因为动态分配的消耗时间是不确定的。

程序在内存管理中常涉及3个操作:

  • 分配某个大小的内存块;
  • 释放一个之前分配的内存块;
  • 垃圾收集:寻找不再使用的内存并予以释放;

C++内部没有垃圾收集机制,需要开发者灵活掌握内存的管理;垃圾回收机制看似友好,但间隔性地释放空间会带来碎片化的内存,过多的碎片在内存中会阻碍一次性分配连续的大容量空间。

RAII(Resource Acquisition Is Initialization)是C++特有的资源管理方式,RAII依托于栈和析构函数对所有资源进行管理;RAII有较成熟的智能指针:std::auto_ptr

C++中几种变量的对比

栈和堆中的变量对比:

  • 1.作用域:栈区域变量的作用域限于函数体内(即{...}),而堆区域变量作用于整个程序,由关键字new开始,由delete结束;
  • 2.编译期间大小确定:栈区变量大小的范围在编译期间就已经确定好,但堆区变量大小的范围需要在运行期间确定;
  • 3.空间范围对比:对于栈区,Windows系统默认栈大小为1M,Linux默认栈大小为8M或10M(通过ulimit -s查看),对于堆区,所有系统的堆空间上限接近内存(虚拟内存)的总大小;开发中,不要将大量数据在栈空间操作,容易引起栈的溢出;
  • 4.内存分配方式:栈区内存分配的地址由高到低,堆区内存分配的地址则是由低到高;
  • 5.两个区的变量均可变;

全局存储区和常量区的对比:

  • 1.存储内容:全局存储区保存全局变量和静态变量,常量区保存常量;
  • 2.全局变量,静态变量和常量在编译期间就确定;
  • 3.全局区的变量可变,常量区不可变;

内存泄漏

内存泄漏(Memory Leak)是指:程序中已经动态分配的堆内存由于未释放,造成系统内存的浪费,导致程序运行速度变慢甚至引起崩溃;

内存泄漏发生原因和排查方式:

  • 内存泄漏主要发生在堆内存的分配,在配置内存后,指向该内存的指针丢失了,这块内存就无法归还给系统;
  • 因为内存泄漏属于程序运行中的问题,无法通过编译识别,所以需要在运行过程中进行诊断;

在堆区申请内存后,适当时机需要记得释放,否则会引起内存泄漏,释放方式如下:

//假设有以下资源
int* p2=NULL;	//stack 栈区变量
p2=new int(20);	//heap 堆区变量

char* p4=new char[7];

//释放堆区分配的变量
if(p2 != NULL)
{
	delete p2;
	p2=NULL;
}
if(p2 != NULL)
{
	delete[] p4;
	p4=NULL;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值