`
fireDragonpzy
  • 浏览: 445196 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

C++内存基础(二)堆栈与函数调用(精)

阅读更多
一、

1) 在栈上创建。在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,一般使用寄存器来存取,效率很高,但是分配的内存容量有限。                                                                                            
2) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete来释放内存。动态内存的生存期由程序员自己决定,使用非常灵活。                      
3) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序整个运行期间都存在,例如全局变量,static变量。
4) 文字常量分配在文字常量区,程序结束后由系统释放。                                                                      
5)程序代码区。
实例:
#i nclude <string>
int a=0;    //全局初始化区 
char *p1;   //全局未初始化区 
void main() 
{ 
    int b;//栈 
    char s[]="abc";   //栈 
    char *p2;         //栈
    char *p3="123456";   //123456\0在常量区,p3在栈上
    static int c=0;   //全局(静态)初始化区 
    p1 = (char*)malloc(10); 
    p2 = (char*)malloc(20);   //分配得来得10和20字节的区域就在堆区
    strcpy(p1,"123456");//123456\0放在常量区,编译器可能会将它与p3所向"123456\0"优化成一个地方
}
二、 三种内存对象的比较


  栈对象的优势是在适当的时候自动生成,又在适当的时候自动销毁,不需要程序员操心;而且栈对象的创建速度一般较堆对象快,因为分配堆对象时,会调用operator new操作,operator new会采用某种内存空间搜索算法,而该搜索过程可能是很费时间的,产生栈对象则没有这么麻烦,它仅仅需要移动栈顶指针就可以了。但是要注意的是,通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。特别要注意递归函数中最好不要使用栈对象,因为随着递归调用深度的增加,所需的栈空间也会线性增加,当所需栈空间不够时,便会导致栈溢出,这样就会产生运行时错误。 
  堆对象创建和销毁都要由程序员负责,所以,如果处理不好,就会发生内存问题。如果分配了堆对象,却忘记了释放,就会产生内存泄漏;而如 果已释放了对象,却没有将相应的指针置为NULL,该指针就是所谓的“悬挂指针”,再度使用此指针时,就会出现非法访问,严重时就导致程序崩溃。但是高效的使用堆对象也可以大大的提高代码质量。比如,我们需要创建一个大对象,且需要被多个函数所访问,那么这个时候创建一个堆对象无疑是良好的选择,因为我们通过在各个函数之间传递这个堆对象的指针,便可以实现对该对象的共享,相比整个对象的传递,大大的降低了对象的拷贝时间。另外,相比于栈空间,堆的容量要大得多。实际上,当物理内存不够时,如果这时还需要生成新的堆对象,通常不会产生运行时错误,而是系统会使用虚拟内存来扩展实际的物理内存。
  静态存储区。所有的静态对象、全局对象都于静态存储区分配。关于全局对象,是在main()函数执行前就分配好了的。其实,在main()函数中的显示代 码执行之前,会调用一个由编译器生成的_main()函数,而_main()函数会进行所有全局对象的的构造及初始化工作。而在main()函数结束之 前,会调用由编译器生成的exit函数,来释放所有的全局对象。比如下面的代码:

int main()
{
......//显示代码
}
实际上,被转化成这样:
void main(void)
{
_main(); //隐式代码,由编译器产生,用以构造所有全局对象
… … // 显式代码
… …
exit() ; // 隐式代码,由编译器产生,用以释放所有全局对象
}
    除了全局静态对象,还有局部静态对象通和class的静态成员,局部静态对象是在函数中定义的,就像栈对象一样,只不过,其前面多了个static关键字。局部静态对象的生命期是从其所在函数第一次被调用,更确切地说,是当第一次执行到该静态对象的声明代码时,产生该静态局部对象,直到整个程序结束时,才销毁该对象。class的静态成员的生命周期是该class的第一次调用到程序的结束。

摘自:http://hi.baidu.com/bmrs/blog/item/f3845afcddc17e4cd7887d73.html</string>
分享到:
评论

相关推荐

    C++高效获取函数调用堆栈

    C++ 获取函数调用堆栈的 高效实现代码

    剖析C++函数调用约定

    Visual C/C++的编译器提供了几种函数调用约定,了解这些函数调用约定的含义及它们之间的区别可以帮助我们更好地调试程序。在这篇文章里,我就和大家共同探讨一些关于函数调用约定的内容。 Visual C/C++的编译器支持...

    堆栈、栈帧与函数调用过程分析

    【应聘笔记系列】堆栈、栈帧与函数调用过程分析,C-C++堆栈指引

    函数调用与堆栈

    自动生存期:局部变量和函数形参一般都具有自动生存期,它们的内存空间在程序执行到定义它们的复合语句(包括函数体)时才分配,当定义它们的复合语句执行结束时内存被收回。 动态生存期:具有动态生存期的变量的生存...

    通过EBP EIP来找函数调用堆栈

    通过EBP EIP来找函数调用堆栈 通过EBP EIP来找函数调用堆栈 通过EBP EIP来找函数调用堆栈 通过EBP EIP来找函数调用堆栈

    函数调用约定与函数名称修饰规则

    函数调用约定与函数名称修饰规则-很实用 使用C/C++语言开发软件的程序员经常碰到这样的问题:有时候是程序编译没有问题,但是链接的时候总是报告函数不存在(经典的LNK 2001错误),有时候是程序编译和链接都没有...

    C++函数调用传参与返回值深度分析

    也许你从书上了解到了C++的函数参数和返回值类型有类对象,引用,指针。 但是却不知道在内存中到底是怎么回事。本文档从内存堆栈分别揭示了这6种情况下到底在这个过程中发生了什么事情。

    个人总结--函数堆栈调用

    自己总结了一点C,C++的资料,主要讲空类中的默认函数, 以及函数调用时栈的调用关系.

    C-C++堆栈指引

    【应聘笔记系列】堆栈、栈帧与函数调用过程分析,C-C++堆栈指引

    C++析构函数调用时间及分配对象堆与栈区别demo

    描述了C++析构函数调用时间及分配对象堆与栈区别,一个理清C++析构函数和默认系统析构函数,C++堆栈分配的原则。

    追踪谁调用了函数

    追踪谁调用了函数 堆栈追踪 StackWalk 追踪谁调用了函数 堆栈追踪 StackWalk

    Win32环境下函数调用的堆栈之研究

    Win32环境下函数调用的堆栈之研究 由于阅读《Q版缓冲区溢出教程》的需要理解和掌握栈的相关知识,故而使用VC 6.0工具来研究win32环境下函数调用时具体的栈操作。 阅读本文建议先看结论,大概了解相关概念,再看第4...

    函数调用约定与函数名称修饰规则.pdf

    调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变和由谁来处理堆栈等问题。不同的语言定义了不同的调用约定。 在...

    一个基于 C++的动态内存实时监测器设计与应用

    通过对地球物理软件研发过程中比较常见内存错误的调研与总结,设计并实现了一个基于C/C++的动态内存检测工具, 采用内嵌与关键函数截获方式,对编译器开放接口进行扩展与改进,该工具通过对软件运行过程中堆内存使用...

    C/C++函数调用的几种方式总结

    函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据,并进行计算。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。 在参数传递中,有两个重要的问题必须要...

    利用堆栈回溯、addr2line和Graphviz生成运行时函数调用图

    现在的软件源代码动则千万行,初学者常常感到迷惘,如果能自动生成关键函数的调用关系图,则思路可以清晰许多。如下面这幅图展示了WebKit网页渲染的部分函数执行过程,比单纯地看代码直观多了。 ...

    关于函数调用方式__stdcall和__cdecl详解

    关于函数调用方式__stdcall和__cdecl详解 __stdcall __cdecl 两者的相同点与不同点 实例 __stdcall __stdcall的全称是standard call。是C++的标准调用方式。 函数参数的入栈顺序为从右到左入栈。函数返回时使用retn ...

    从汇编看c++中默认构造函数的使用分析

    ebp为一个寄存器,总是指向一个函数调用堆栈的栈底,作为基址,用偏移量来访问该调用栈上的变量,但这里没有任何变量要访问,因此不起作用 mov ebp, esp;这两句的作用是为了保存调用main之前堆栈的基址ebp的值,并...

    c++中堆栈及创建对象示例代码

    堆(heap),堆包含一个链表来维护已用和空闲的不连续的内存块,存放在二级缓存中,一般由程序员分配释放。 快速记忆方式: 一级缓存比二级缓存快,栈是一个先进后出列表,存取非常快,所以栈是在一级缓存中。 栈中...

    lua5.3实例

    2. function.lua ## 函数调用 3. param.lua ## 函数参数, 4. table ## table 5. e12.lua e13.cpp ## c++调用 lua函数 6. e14.cpp e15.lua ## lua调用c++函数 7. 文件夹class ## lua调用c++类 堆栈形式 8 文件夹...

Global site tag (gtag.js) - Google Analytics