静态分配和动态分配内存的区别

要弄懂这个问题,首先你得知道静态和动态指的是什么。个人觉得卡耐基上的解释很经典:

     “The word static refers to things that happen at compile time and link time when the program is constructed—as opposed to load time or run time when the program is actually started.”

     “The term dynamic refers to things that take place when a program is loaded and executed. ”

      说白了,内存的静态分配和动态分配的区别主要是两个:

        一是时间不同。静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。

      二是空间不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由函数malloc进行分配。不过栈的动态分配和堆不同,他的动态分配是由编译器进行释放,无需我们手工实现。    

       对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。

        一般,用static修饰的变量,全局变量位于静态数据区。函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。



首先,在使用动态分配内存技术前,必须明白自己在做什么,这样做与其它的方法有什么不同,特别是会产生哪些负面影响,天下没有免费的午餐。动态分配内存与静态分配内存的区别:

1) 静态内存分配是在编译时完成的,不需要占用CPU资源;动态分配内存是在运行时完成的,动态内存的分配与释放需要占用CPU资源; 
2) 静态内存分配是在栈上分配的,动态内存是堆上分配的; 
3) 动态内存分配需要指针或引用数据类型的支持,而静态内存分配不需要; 
4) 静态分配内存需要在编译前确定内存块的大小,而动态分配内存不需要编译前确定内存大小,根据运行时环境确定需要的内存块大小,按照需要分配内存即可。可以这么说,静态内存分配是按计划分配,而动态内存分配是按需分配。 
5) 静态分配内存是把内存的控制权交给了编译器,而动态内存是把内存的控制权交给了程序员;

综上所述,静态分配内存适合于编译时就已经可以确定需要占用内存多少的情况,而在编译时不能确定内存需求量时可使用动态分配内存;但静态分配内存的运行效率要比动态分配内存的效率要高,因为动态内存分配与释放需要额外的开销;动态内存管理水平严重依赖于程序员的水平,如果处理不当容易造成内存泄漏。那么再具体些,如何选择内存分配方式,如果动态分配内存需要注意哪些问题呢?

  需要强调的是,由于动态分配内存把内存的控制权交给了程序员,程序员有义务写代码确认内存分配成功能,如果分配失败要做适当处理,否则将给你的程序进而下一个定时炸弹,随时有可能因为动态内存分配失败而导致程序崩溃。

1. 全局变量尽可能不要动态分配内存。

  既然将变量定义为全局变量,就为了其可见范围比较宽,因为可能这些变量在整个程序的运行期都是可见的,可能根本就没有机会释放全局变量所占用的内存,所以使用动态分配内存是意义不大的,只能给程序带来额外的运行负担。 
  但对于全局变量内存大小不能确定的情况,可能会有例外。比如要处理一批数据,数据的大小可能由用户通过控制台参数形式告诉程序,这种情况可以动态按需分配内存,合理使用内存。 
  而对于编译时能够确定内存使用量的全局变量,而且变量工作期(暂且这么叫吧,就是该变量还可能会被用到的这段时期)又与程序的运行期相同的情况根本没有必要动态分配内存。这种情况很有意思,就是使用动态分配内存,但可以不考虑释放这块内存,因为可以释放内存的时候该程序也要退出了,程序一结束,进程也就结束了,整个程序所在的虚拟空间已经被全部释放,也就没必要去添加释放内存的代码了。(但我确定见到过这样的代码)

2. 动态分配内存时,分配与释放的代码要对称。

  这里说的分配与释放的代码对称指,分配内存的代码要与释放内存的代码在同一个范围的代码域中,例如在一个函数的开头申请内存,就应该在这个函数的结尾释放内存,否则,如果在一个函数内部分配内存,在函数外释放内存,就有可能因程序员的疏忽造成内存泄漏;如果内存分配在某个类的构造函数中,那么就应该在析构函数中释放内存,千不要在另外一个函数中释放,而等着客户代码去掉用那个函数去手动释放内存,如果那样的话就相当于埋了一个定时炸弹,随时可能因为一时的疏忽而造成内存泄漏。

3. 对动态创建的对象或分配的内存块一定要检查期有效性。

  由于操作系统的并发性和复杂性,任何一次动态内存的分配操作都有可能失败,特别是申请一次较大块内存时。所以一定要检查动态创建的对象或申请的堆内存是否成功,否则可能因为错误的指针或空指针造成程序异常,如果异常没有得到适当处理的话,可能使整个程序意外终止,造成损失。

4. 尽可能少次数地使用动态内存分配。

  动态分配是在运行时由操作系统完成的,所以是要消耗CPU资源的,在进行动态内存分配时尽可能便利已经分配的资源。如果上次申请的资源够用就不要重新申请资源,不够用时才释放旧资源,申请新资源。

5. 在保证资源利用率的前提下,能用静态内存分配不用动态分配,特别是局部临时对象。

  例如,对于局部对象,使用静态分配的内存,可以由编译器编译时分配,超出作用域自动内存,不仅减小了程序代码,减少了错误产生的概率,减轻了程序员的负担,而且提高的程序的执行效率,何乐而不为呢?


 

 

其它:

所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

例如我们定义一个float型数组:float score[100];   

但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道我们要定义的这个数组到底有多大,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道你想利用的空间大小,但是如果因为某种特殊原因空间利用的大小有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。

我们用动态内存分配就可以解决上面的问题. 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于景泰内存分配的特点:

   1、不需要预先分配存储空间;

   2、分配的空间可以根据程序的需要扩大或缩小。

要实现根据程序的需要动态分配存储空间,就必须用到malloc函数.

malloc函数的原型为:void *malloc (unsigned int size) 其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操作。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值