什么存储在堆上,什么存储在堆栈上?

任何人都可以清楚地解释,在C,C ++和Java方面。 什么是堆栈,什么都在堆上,什么时候分配完成。

我所知道的,

所有局部变量,无论是基元,指针还是每个函数调用的引用变量都在新的堆栈帧上。

而用new或malloc创建的任何东西都会堆积如山。

我对几件事感到困惑。

作为在堆上创建的对象成员的引用/基元也存储在堆上吗?

以及那些在每一帧中递归创建的方法的本地成员呢? 它们全都在堆栈中,如果是,那么在运行时是否分配了堆栈内存? 也是文字,它们是代码段的一部分吗? 以及C中的全局变量,C ++ / Java中的静态变量和C中的静态变量。


记忆中程序的结构

下面是加载到内存中的任何程序的基本结构。

 +--------------------------+
 |                          |
 |      command line        |
 |        arguments         |
 |    (argc and argv[])     |
 |                          |
 +--------------------------+
 | Stack                    |
 | (grows-downwards)        |
 |                          |
 |                          |
 |                          |
 |         F R E E          |
 |        S P A C E         |
 |                          |
 |                          |
 |                          |
 |                          |
 |     (grows upwards) Heap |
 +--------------------------+
 |                          |
 |    Initialized data      |
 |         segment          |
 |                          |
 +--------------------------+
 |                          |
 |     Initialized to       |
 |        Zero (BSS)        |
 |                          |
 +--------------------------+
 |                          |
 |      Program Code        |
 |                          |
 +--------------------------+

几点要注意:

  • 数据段
  • 初始化数据段(由程序员初始化为显式初始化程序)
  • 未初始化的数据段(初始化为零数据段 - BSS [用符号块开始])
  • 代码段
  • 堆栈和堆区域
  • 数据段

    数据段包含由包含初始化值的用户明确初始化的全局数据和静态数据。

    数据段的另一部分称为BSS(因为旧的IBM系统已将该段初始化为零)。 它是操作系统初始化内存块为零的内存部分。 这就是未初始化的全局数据和静态获取默认值为零的方式。 这个区域是固定的并且具有静态大小。

    根据显式初始化将数据区分为两个区域,因为要初始化的变量可以逐个初始化。 但是,未初始化的变量不需要用0逐个显式初始化。 取而代之的是,初始化变量的工作留给操作系统。 这种批量初始化可以大大减少加载可执行文件所需的时间。

    大部分数据段的布局都在底层操作系统的控制之下,还有一些加载器对用户进行部分控制。 这些信息可能在诸如嵌入式系统等应用程序中很有用。

    这个区域可以使用来自代码的指针进行寻址和访问。 自动变量在每次需要时初始化变量时都会产生开销,并且需要代码来执行初始化。 但是,数据区域中的变量没有这种运行时过载,因为初始化只在加载时进行一次。

    代码段

    程序代码是可执行代码可用于执行的代码区域。 这个区域也是固定的大小。 这只能被函数指针访问,而不能被其他数据指针访问。 这里需要注意的另一个重要信息是,系统可能将该区域视为只读存储区,并且任何在此区域写入的尝试都会导致未定义的行为。

    常量字符串可以放在代码或数据区域中,这取决于实现。

    尝试写入代码区会导致未定义的行为。 例如(我只给出基于C的示例)下面的代码可能会导致运行时错误甚至崩溃系统。

    int main()
    {
        static int i;
        strcpy((char *)main,"something");
        printf("%s",main);
        if(i++==0)
        main();
    }
    

    堆栈和堆区

    为了执行,程序使用两个主要部分,堆栈和堆。 堆栈帧被创建为堆栈以实现动态内存分配。 堆栈和堆是未初始化的区域。 因此,无论在内存中发生什么,都会成为在该空间中创建的对象的初始(垃圾)值。

    让我们看一个示例程序来显示哪些变量存储在哪里,

    int initToZero1;
    static float initToZero2;
    FILE * initToZero3; 
    // all are stored in initialized to zero segment(BSS)
    
    double intitialized1 = 20.0;
    // stored in initialized data segment
    
    int main()
    {
        size_t (*fp)(const char *) = strlen;
        // fp is an auto variable that is allocated in stack
        // but it points to code area where code of strlen() is stored
    
        char *dynamic = (char *)malloc(100);
        // dynamic memory allocation, done in heap
    
        int stringLength;
        // this is an auto variable that is allocated in stack
    
        static int initToZero4; 
        // stored in BSS
    
        static int initialized2 = 10; 
        // stored in initialized data segment   
    
        strcpy(dynamic,”something”);    
        // function call, uses stack
    
        stringLength = fp(dynamic); 
        // again a function call 
    }
    

    或者考虑一个更复杂的例子,

    // command line arguments may be stored in a separate area  
    int main(int numOfArgs, char *arguments[])
    { 
        static int i;   
        // stored in BSS 
    
        int (*fp)(int,char **) = main;  
        // points to code segment 
    
        static char *str[] = {"thisFileName","arg1", "arg2",0};
        // stored in initialized data segment
    
        while(*arguments)
            printf("n %s",*arguments++);
    
        if(!i++)
            fp(3,str);
    }
    

    希望这可以帮助!


    在C / C ++中:局部变量分配在当前栈帧上(属于当前函数)。 如果静态分配一个对象,则整个对象将被分配到堆栈中,包括其所有成员变量。 当使用递归时,每个函数调用都会创建一个新的堆栈帧,并且所有局部变量都将被分配到堆栈中。 堆栈通常具有固定的大小,并且这个值通常在编译/链接过程中写入可执行二进制头文件中。 然而,这是非常特定的操作系统和平台,有些操作系统可能会在需要时动态增加堆栈。 因为堆栈的大小通常是有限的,所以当你使用深递归时,或者有时甚至在没有递归的情况下,当静态分配大对象时,你可能会用完堆栈。

    堆通常被视为一个无限空间(仅受限于可用的物理/虚拟内存),并且您可以使用malloc / new(以及其他堆分配函数)在堆上分配对象。 当在堆上创建对象时,其所有成员变量都将在其中创建。 你应该看到一个对象作为一个连续的内存区域(这个区域包含成员变量和一个虚拟方法表的指针),而不管它在哪里分配。

    文字,常量和其他“固定”的东西通常编译/链接到二进制文件作为另一个段,所以它不是真的是代码段。 通常你不能在运行时分配或释放这个段的任何东西。 然而,这也是特定于平台的,它可能在不同的平台上有不同的工作方式(例如,iOS Obj-C代码中有很多常量引用直接插入到代码段中,函数之间)。


    在C和C ++中,至少,这是所有特定于实现的。 标准没有提到“堆栈”或“堆”。

    链接地址: http://www.djcxy.com/p/82737.html

    上一篇: What is stored on heap and what is stored on stack?

    下一篇: Do stack and heap memory both refer to the RAM(Assume no paging is being used)?