`
心动音符
  • 浏览: 342355 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

栈对象、堆对象、静态对象的比较

 
阅读更多
栈对象的优势是在适当的时候自动生成,又在适当的时候自动销毁,不需要程序员操心;

而且栈对象的创建速度一般较堆对象快,因为分配堆对象时,会调用operator new操作,operator new会采用某种内存空间搜索算法,而该搜索过程可能是很费时间的,产生栈对象则没有这么麻烦,它仅仅需要移动栈顶指针就可以了。

但是要注意的是,通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。特别要注意递归函数中最好不要使用栈对象,因为随着递归调用深度的增加,所需的栈空间也会线性增加,当所需栈空间不够时,便会导致栈溢出,这样就会产生运行时错误。   

堆对象,其产生时刻和销毁时刻都要程序员精确定义,也就是说,程序员对堆对象的生命具有完全的控制权。我们常常需要这样的对象,比如,我们需要创建一个对象,能够被多个函数所访问,但是又不想使其成为全局的,那么这个时候创建一个堆对象无疑是良好的选择,然后在各个函数之间传递这个堆对象的指针,便可以实现对该对象的共享。

另外,相比于栈空间,堆的容量要大得多。实际上,当物理内存不够时,如果这时还需要生成新的堆对象,通常不会产生运行时错误,而是系统会使用虚拟内存来扩展实际的物理内存。

接下来看看static对象。   

首先是全局对象。全局对象为类间通信和函数间通信提供了一种最简单的方式,虽然这种方式并不优雅。一般而言,在完全的面向对象语言中,是不存在全局对象的,比如C#,因为全局对象意味着不安全和高耦合,在程序中过多地使用全局对象将大大降低程序的健壮性、稳定性、可维护性和可复用性。C++也完全可以剔除全局对象,但是最终没有,我想原因之一是为了兼容C。   

其次是类的静态成员,上面已经提到,基类及其派生类的所有对象都共享这个静态成员对象,所以当需要在这些class之间或这些class objects之间进行数据共享或通信时,这样的静态成员无疑是很好的选择。   

接着是静态局部对象,主要可用于保存该对象所在函数被屡次调用期间的中间状态,其中一个最显著的例子就是递归函数,我们都知道递归函数是自己调用自己的函数,如果在递归函数中定义一个nonstatic局部对象,那么当递归次数相当大时,所产生的开销也是巨大的。这是因为nonstatic局部对象是栈对象,每递归调用一次,就会产生一个这样的对象,每返回一次,就会释放这个对象,而且,这样的对象只局限于当前调用层,对于更深入的嵌套层和更浅露的外层,都是不可见的。每个层都有自己的局部对象和参数。   

在递归函数设计中,可以使用static对象替代nonstatic局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic对象的开销,而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。

======================

在gameres上看见一个问题帖:

什么时候该用 Object object;

什么时候该用 Object *object;
             object=new Object();

感觉看起来没什么区别,其实不一样:前一个是栈对象,后一个是堆对象。

引用一下别人对栈对象、堆对象的解释:

  栈对象的优势是在适当的时候自动生成,又在适当的时候自动销毁,不需要程序员操心;而且栈对象的创建速度一般较堆对象快,因为分配堆对象时,会调用 operator new操作,operator new会采用某种内存空间搜索算法,而该搜索过程可能是很费时间的,产生栈对象则没有这么麻烦,它仅仅需要移动栈顶指针就可以了。但是要注意的是,通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。特别要注意递归函数中最好不要使用栈对象,因为随着递归调用深度的增加,所需的栈空间也会线性增加,当所需栈空间不够时,便会导致栈溢出,这样就会产生运行时错误。

  堆对象,其产生时刻和销毁时刻都要程序员精确定义,也就是说,程序员对堆对象的生命具有完全的控制权。我们常常需要这样的对象,比如,我们需要创建一个对象,能够被多个函数所访问,但是又不想使其成为全局的,那么这个时候创建一个堆对象无疑是良好的选择,然后在各个函数之间传递这个堆对象的指针,便可以实现对该对象的共享。另外,相比于栈空间,堆的容量要大得多。实际上,当物理内存不够时,如果这时还需要生成新的堆对象,通常不会产生运行时错误,而是系统会使用虚拟内存来扩展实际的物理内存。

所以
当你知道你要使用的类型拥有准确数量时使用 Object object;
当你不知道你要创建的类型有多少个时使用
Object *object;
object=new Object();

=================

先说一下局部对象的性质,在第一次执行到的时候初始化,而在最后的时候析构,也就是说如果它生成后,在程序的运行期,它都是有效的,存在于静态存储区,尽管它往往不是时时可见,但可以经由指针操作它,因为它一直都在。

       使用局部静态对象的Singleton就是这个原理,解决的主要问题是Singleton的析构问题。本书中,对局部静态对象的处理还是很巧妙的。我写的测试程序也证明了局部静态对象的性质,无论访问对象定义多少次,始终只有一次对象构造和析构
分享到:
评论

相关推荐

    C++_静态存储区_栈_堆的区别

    与栈不同,堆是在运行时动态分配的内存区域,主要用于存储动态创建的对象和数组。在C++中,你可以使用`new`操作符在堆上分配内存,使用`delete`操作符释放内存。堆的分配和释放过程较慢,因为它涉及到搜索合适的空闲...

    c++如何控制对象的创建方式(禁止创建栈对象or堆对象)和创建的数量

    C++ 中对象的创建方式可以分为栈对象、堆对象和静态对象三种。通常情况下,对象创建在堆上还是栈上,创建多少个都是没有限制的。但有时会遇到一些特殊需求,例如禁止创建栈对象或禁止创建堆对象。本文将详细介绍如何...

    C++堆、栈及静态数据区详解

    本文将深入探讨C++中的堆、栈以及静态数据区,帮助理解这些内存区域的区别和使用场景。 1. 栈(Stack): 栈是编译器自动管理的内存区域,主要用来存放函数参数、局部变量等。每当进入一个函数调用,栈就会为函数的...

    C++ 静态存储区 栈 堆的区别.txt

    ### C++中的静态存储区、栈与堆的区别 在C++编程语言中,根据变量的存储方式和生命周期,可以将内存区域大致分为四个部分:静态存储区、栈、堆以及未初始化的数据段(BSS)。其中,静态存储区、栈与堆是程序运行时...

    C/C++堆、栈及静态数据区详解

    内存被划分为五个主要区域:堆、栈、自由存储区、全局/静态存储区和常量存储区。 1. **栈(Stack)**: 栈是程序运行时用于存放临时数据的地方,如局部变量和函数参数。栈由编译器自动管理,当函数调用结束或局部...

    内存分配——静态存储区 栈 堆.doc

    ### 内存分配详解:静态存储区、栈与堆 #### 一、内存基本构成 在计算机编程中,内存管理是十分重要的一个方面。合理的内存分配不仅能够提高程序的运行效率,还能有效避免一些常见的编程错误,比如内存泄漏。本文...

    内存中堆和栈的分配区别

    静态变量`static int c`虽然在全局空间,但也属于静态存储类别,不同于栈和堆。 ### 性能考量 在选择使用栈还是堆时,性能是一个重要的考量因素。对于频繁访问且生命周期较短的小型数据,使用栈可以提高程序的执行...

    变量在Java栈、堆内存中的运用管理分析.pdf

    `,`str`在栈中存储的是指向堆内存中对象的引用,而非对象本身。这个引用使得栈中的变量可以访问堆中的对象。 3. 堆内存 堆内存主要存放new关键字创建的对象和数组。由于对象可能包含多个成员变量,它们在堆中按需...

    JAVA中堆、栈,静态方法和非静态方法的速度问题

    JAVA中堆、栈、静态方法和非静态方法的速度问题 JAVA中堆、栈是JVM内存模型中的两个重要...堆和栈的速度性能分析可以从多角度来分析,而静态方法和非静态方法的速度比较也需要考虑到对象的初始化和方法的调用方式。

    用new创建对象和直接定义的区别

    6. **内存泄漏**:忘记删除`new`创建的对象可能导致内存泄漏,而栈对象不存在这个问题。 总的来说,选择哪种方式创建对象取决于应用场景和需求。对于短暂存在、生命周期明确的对象,直接定义可能更合适;而对于需要...

    Java中堆内存和栈内存详解

    Java的内存分配策略主要包括静态分配、栈式分配和堆式分配。其中,栈式分配和堆式分配是运行时动态进行的,具体如下: 1. **栈式存储分配**:栈式存储适用于已知大小的局部变量和方法参数。当一个方法被调用时,JVM...

    堆和栈的讲解

    - **堆**:内容由程序员决定,一般用于动态数据存储,如动态数组或对象实例。 ##### 2.6 存取效率的比较 在存取效率上,栈上的数据比堆上的数据访问更快。这是因为栈中的数据存储在CPU寄存器附近,访问速度极快。...

    c++ 类与对象课件,包括对象的初始化,对象的使用,构造函数和析构函数等等

    栈对象的生命周期由其作用域决定,而堆对象需要程序员手动管理其生命周期。 理解并掌握这些知识点,将有助于编写出更加高效、健壮的C++代码。在实际编程中,应灵活运用面向对象的设计原则,如单一职责原则、开闭...

    从JVM内存管理的角度谈谈静态方法和静态属性

    当调用非静态方法时,必须先创建对象实例,这样栈中才会有一个指向堆中对象实例的指针。这个指针使得实例方法能够访问并修改对象的属性。 静态属性同样不依赖于任何对象实例,它们属于类本身,而不是类的任何实例。...

    静态全局变量 静态数据成员 静态顺序栈.rar

    `静态顺序栈的简单应用--进制转换.cpp`可能包含了一个使用静态顺序栈进行进制转换的示例。 这些文件名表明,每个源代码文件可能专注于一个特定的静态特性,通过注释详细解释了它们的工作原理和使用场景。学习和理解...

    Java中堆内存与栈内存分配浅析

    静态存储分配在编译时就确定了变量的内存需求,栈式分配在运行时按需分配,而堆式分配则处理编译时和运行时都无法确定存储需求的数据结构,如可变长度的字符串和对象实例。 在Java中,堆内存和栈内存的比较可以从...

    堆和栈的区别——软件常识

    总的来说,栈适合存储生命周期短、大小固定的对象,而堆适合存储生命周期不确定或大小不固定的对象。在实际编程中,合理使用堆和栈可以提高程序的性能和内存利用效率。此外,了解操作系统如何管理内存,如使用`...

    堆和栈的区别

    ### 堆和栈的区别详解 #### 一、引言 在编程中,了解不同内存区域的特点及其使用方法是非常重要的。...例如,对于频繁使用的、生命周期较短的数据结构推荐使用栈,而对于生命周期不确定或较大的对象则推荐使用堆。

    堆内存和栈内存详解 ESP

    - 堆内存虽然分配较慢,但对于需要长时间存在的对象来说更加合适。 #### 三、示例分析 考虑以下C语言代码片段: ```c #include #include char *AllocStrFromStack() { char pstr[100]; return pstr; } ...

Global site tag (gtag.js) - Google Analytics