`
fireDragonpzy
  • 浏览: 462747 次
  • 性别: 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++函数调用约定

    C++函数调用约定是编程过程中非常重要的概念,它规定了函数调用时参数传递的顺序、谁负责清理堆栈以及函数名是否需要修饰。在Visual C/C++编译器中,有四种主要的函数调用约定:__cdecl、__stdcall、__fastcall和...

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

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

    C#调用C++动态库,执行回调函数并传递结构体参数

    C++的回调函数需要考虑函数指针的调用约定,通常使用`__stdcall`约定,以确保调用者清理堆栈。 在C#中定义回调函数的委托类型: ```csharp [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void ...

    函数调用与堆栈

    ### 函数调用与堆栈 #### 变量的生存期概述 在计算机编程中,尤其是在C/C++这类语言中,变量的生存期是指变量在程序执行过程中占据内存的时间段。根据变量生存期的不同,我们可以将变量大致分为三类:静态生存期...

    C C++语言函数参数传递及函数调用约定的探讨

    ### C/C++语言函数参数传递及函数调用约定的探讨 #### 摘要 本文主要探讨了C/C++语言中函数之间的参数传递机制以及计算机如何处理函数调用中的参数,即函数调用约定。文章重点分析了值传递与地址传递这两种主要的...

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

    本文将重点讨论函数调用时的堆栈操作,特别是与C++中的空类和默认函数相关的内容。 首先,让我们来看看空类`Empty`。在C++中,一个没有任何成员变量的类被称为空类。即使类是空的,编译器也会自动为类生成一些默认...

    VC中打印当前调用堆栈信息实例

    在Microsoft Visual C++ (VC) 开发环境中,打印当前调用堆栈信息是一个非常有用的调试技巧,它可以帮助开发者追踪程序执行流程,理解函数调用顺序,尤其是在遇到异常或错误时。下面将详细介绍如何在VC中实现这个功能...

    函数调用过程种种细节分析

    堆栈帧的存在使得多个函数调用能够同时存在于内存中,而不会相互干扰。 接下来,我们讨论函数调用。函数调用是一个过程,其中一个函数通过其名称被引用并传递参数,然后控制权转移到该函数的代码。这个过程包括以下...

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

    在计算机科学中,特别是在软件调试和逆向工程领域,理解函数调用堆栈是至关重要的。函数调用堆栈(也称为调用栈或执行栈)记录了程序中函数调用的顺序,这对于追踪代码执行流程,特别是错误定位非常有用。在x86架构...

    C++ Dump 内存快照的实现

    1. **监控内存分配**:你需要拦截系统或库的内存分配函数,如`malloc`、`new`、`calloc`等,记录下每次分配的内存信息,包括分配的大小、地址、调用堆栈等。 2. **跟踪内存释放**:同样,你需要拦截内存释放函数如`...

    关于C和C++中函数的调用约定.doc

    在C和C++编程中,函数的调用约定(Calling ...总之,理解并正确使用函数调用约定和函数名修饰规则是避免C和C++程序中常见错误的关键。正确应用这些规则可以保证程序的正确链接和执行,提高代码的兼容性和可维护性。

    Visual C++中函数调用方式浅探

    Visual C++中函数调用方式浅探 在 Visual C++ 中,函数调用方式是一个非常重要的概念。不同的函数调用方式会对程序的执行和性能产生影响。在 C 和 C++ 中,默认的函数调用方式是 C 式调用,也就是 __cdecl。除非...

    追踪谁调用了函数

    通过遍历这个堆栈,我们可以逆序地查看函数调用的顺序,从而得知哪些函数调用了目标函数。 在C++中,实现堆栈追踪通常有两种方法: 1. **利用编译器支持**:一些编译器如GCC和Visual C++提供了内置的函数来获取...

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

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

    c++内存检测(防止堆栈错误)

    栈内存由编译器自动管理,用于存储局部变量和函数调用信息;而堆内存则需要程序员手动分配和释放,通常用于动态创建大对象或数组。 内存泄漏是常见的堆栈错误之一,它发生在程序分配了内存但没有正确释放。为了避免...

    Visual C++中函数调用方式浅探.docx

    "Visual C++中函数调用方式浅探" Visual C++中函数调用方式浅探概述: 在Visual C++中,函数调用方式可以分为两种:C式调用和Pascal式调用。其中,C式调用是缺省的,除非特殊声明。在本文中,我们将详细探讨这两种...

    数据结构C++语言(进出堆栈动画)

    堆栈是一种后进先出(Last In First Out,简称LIFO)的数据结构,常用于实现函数调用、表达式求值、内存管理等多种场景。在C++中,堆栈可以通过标准模板库(Standard Template Library,简称STL)中的`stack`容器来...

    BugTrap - C++程序崩溃堆栈信息收集

    通常,堆栈信息包括了出错前的函数调用链,帮助开发者了解代码执行的上下文。 使用BugTrap的步骤大致如下: 1. **集成BugTrap库**:首先,你需要将BugTrap的库文件添加到你的C++项目中。在提供的`BugTrap-master`...

Global site tag (gtag.js) - Google Analytics