精华内容
下载资源
问答
  • 我们在写程序时,既有程序的逻辑代码,也有在程序中定义的变量等数据,那么当我们的程序进行时,我们的代码数据究竟是存放在哪里的呢?下面就来总结一下。 一、程序运行时的内存空间情况 其实在程序...
    我们在写程序时,既有程序的逻辑代码,也有在程序中定义的变量等数据,那么当我们的程序进行时,我们的代码和数据究竟是存放在哪里的呢?下面就来总结一下。
    

    一、程序运行时的内存空间情况

    其实在程序运行时,由于内存的管理方式是以页为单位的,而且程序使用的地址都是虚拟地址,当程序要使用内存时,操作系统再把虚拟地址映射到真实的物理内存的地址上。所以在程序中,以虚拟地址来看,数据或代码是一块块地存在于内存中的,通常我们称其为一个段。而且代码和数据是分开存放的,即不储存于同于一个段中,而且各种数据也是分开存放在不同的段中的。

    下面以一个简单的程序来看一下在Linux下的程序运行空间情况,代码文件名为space.c
    1. #include <unistd.h>  
    2. #include <stdio.h>  
    3.   
    4. int main()  
    5. {  
    6.     printf("%d\n", getpid());  
    7.     while(1);  
    8.     return 0;  
    9. }  

    这个程序非常简单,输出当前进程的进程号,然后进入一个死循环,这个死循环的目的只是让程序不退出。而在Linux下有一个目录/proc/$(pid),这个目录保存了进程号为pid的进程运行时的所有信息,其中有一个文件maps,它记录了程序执行过程中的内存空间的情况。编译运行上面的代码,其运行结果如图1所示:


    从上面的图中,我们可以看到这样一个简单的程序,在执行时,需要哪些库和哪些空间。上面的图的各列的意思,不一一详述,只对重要的进行说明。
    第一列的是一个段的起始地址和结束地址,第二列这个段的权限,第三列段的段内相对偏移量,第六列是这个段所存放的内容所对应的文件。从上图可以看到我们的程序进行首先要加载系统的两个共享库,然后再加载我们写的程序的代码。

    对于第二列的权限,r:表示可读,w:表示可写,x:表示可执行,p:表示受保护(即只对本进程有效,不共享),与之相对的是s,意是就是共享。

    从上图我们可以非常形象地看到一个程序进行时的内存分布情况。下面我们将会结合上图,进行更加深入的对内存中的数据段的解说。

    二、程序运行时内存的各种数据段

    1.bss段
    该段用来存放没有被初始化或初始化为0的全局变量,因为是全局变量,所以在程序运行的整个生命周期内都存在于内存中。有趣的是这个段中的变量只占用程序运行时的内存空间,而不占用程序文件的储存空间。可以用以下程序来说明这点,文件名为bss.c
    1. #include <stdio.h>  
    2.   
    3. int bss_data[1024 * 1024];  
    4.   
    5. int main()  
    6. {  
    7.     return 0;  
    8. }  
    这个程序非常简单,定义一个4M的全局变量,然后返回。编译成可执行文件bss,并查看可执行文件的文件属性如图2所示:


    从可执行文件的大小4774B可以看出,bss数据段(4M)并不占用程序文件的储存空间,在下面的data段中,我们可以看到data段的数据是占用可执行文件的储存空间的。

    在图1中,有文件名且属性为rw-p的内存区间,就是bss段。

    2.data段
    初始化过的全局变量数据段,该段用来保存初始化了的非0的全局变量,如果全局变量初始化为0,则编译有时会出于优化的考虑,将其放在bss段中。因为也是全局变量,所以在程序运行的整个生命周期内都存在于内存中。与bss段不同的是,data段中的变量既占程序运行时的内存空间,也占程序文件的储存空间。可以用下面的程序来说明,文件名为data.c:
    1. #include <stdio.h>  
    2.   
    3. int data_data[1024 * 1024] = {1};  
    4.   
    5. int main()  
    6. {  
    7.     return 0;  
    8. }  
    这个程序与上面的bss唯一的不同就是全局变量int型数组data_data为每个元素指定了一个初始值1.编译可执行文件data,并查看可执行文件的文件属性如图3所示:


    从可执行文件的大小来看,data段数据(data_data数组的大小,4M)占用程序文件的储存空间。

    在图1中,有文件名且属性为rw-p的内存区间,就是data段,它与bss段在内存中是共用一段内存的,不同的是,bss段数据不占用文件,而data段数据占用文件储存空间。

    3.rodata段
    该段是常量数据段,用于存放常量数据,ro就是Read Only之意。但是注意并不是所有的常量都是放在常量数据段的,其特殊情况如下:
    1)有些立即数与指令编译在一起直接放在代码段(text段,下面会讲到)中。
    2)对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份。
    3)有些系统中rodata段是多个进程共享的,目的是为了提高空间的利用率。

    在图1中,有文件名的属性为r--p的内存区间就是rodata段。可见他是受保护的,只能被读取,从而提高程序的稳定性。

    4.text段
    text段就是代码段,用来存放程序的代码(如函数)和部分整数常量。它与rodata段的主要不同是,text段是可以执行的,而且不被不同的进程共享。

    在图1中,有文件名且属性为r-xp的内存区间就是text段。就如我们所知道的那样,代码段是不能被写的。

    5.stack段
    该段就是栈段,用来保存临时变量和函数参数。程序中的函数调用就是以栈的方式来实现的,通常栈是向下(即向低地址)增长的,当向栈中push一个元素,栈顶指针就会向低地址移动,当从栈中pop一个元素,栈顶指针就会向高地址移动。栈中的数据只在当前函数或下一层函数中有效,当函数返回时,这些数据自动被释放,如果继续对这些数据进行访问,将发生未知的错误。通常我们在程序中定义的不是用malloc系统函数或new出来的变量,都是存放在栈中的。例如,如下函数:
    void func()
    {
        int a = 0;
        int *n_ptr = malloc(sizeof(int));
        char *c_ptr = new char;
    }

    整型变量a,整型指针变量n_ptr和char型指针变量c_ptr,都存放在栈段中,而n_ptr和c_ptr指向的变量,由于是malloc或new出来的,所以存放在堆中。当函数func返回时,a、n_ptr、c_ptr都会被释放,但是n_ptr和c_ptr指向的内存却不会释放。因为它们是存在于堆中的数据。

    在图1中,文件名为stack的内存区间即为栈段。

    6.heap段
    heap(堆)是最自由的一种内存,它完全由程序来负责内存的管理,包括什么时候申请,什么时候释放,而且对它的使用也没有什么大小的限制。在C/C++中,用alloc系统函数和new申请的内存都存在于heap段中。

    以上面的程序为例,它向堆申请了一个int和一个char的内存,因为没有调用free或delete,所以当函数返回时,堆中的int和char变量并没有释放,造成了内存泄漏。

    由于在图1所对应的代码中没有使用alloc系统函数或new来申请内存,所以heap段并没有在图1中显示出来,所以以下面的程序来说明heap段的位置,代码文件为heap.c,代码如下:
    1. #include <unistd.h>  
    2. #include <stdlib.h>  
    3. #include <stdio.h>  
    4.   
    5. int main()  
    6. {  
    7.     int *n_ptr = malloc(sizeof(int));  
    8.     printf("%d\n", getpid());  
    9.     while(1);  
    10.     free(n_ptr);  
    11.     return 0;  
    12. }  
    查看其运行时内存空间分布如下:


    可以看到文件名为heap的内存区间就是heap段。从上图,也可以看出,虽然我们只申请4个字节(sizeof(int))的空间,但是在操作系统中,内存是以页的方式进行管理的,所以在分配heap内存时,还是一次分配就为我们分配了一个页的内存。注:无论是图1,还是上图,都有一些没有文件名的内存区间,其实没用文件名的内存区间表示使用mmap映射的匿名空间。
    展开全文
  • int数据存放时第一位是高地址还是低地址,就是比如我存放1是按00000001还是01000000
  • 1.函数代码存放代码段。声明的类如果从未使用,则在编译时,会优化掉,其成员...BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。 BSS是英文Block Started by Symbol的简称...

    1.函数代码存放在代码段。声明的类如果从未使用,则在编译时,会优化掉,其成员函数不占代码段空间。

    全局变量或静态变量,放在数据段,
    局部变量放在栈中,
    用new产生的对象放在堆中,

    内存分为4段,栈区,堆区,代码区,全局变量区

    BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
    BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

    2.代码段、数据段、栈是CPU级别的逻辑概念,堆是语言级别的逻辑概念

    3.还有一个常量区,其中的内容不许修改。
    常见的 char *p = "hello"; 这里面的"hello"就保存在常量区

    4.如1楼所说,把代码段、数据段,栈,堆这些并列在一起不太合适
    代码段、数据段、堆栈段,这是一个概念
    堆、栈、全局区、常量区,这是另一个概念

    5.STACK(栈)临时局部
    HEAP(堆)动态
    RW(读写)全局
    RO(只读)代码
    Char* s=”Hello,World”; S中“H”存放在内存RO中且不能修改。

    6.CPU寄存器:CPU寄存器,其实就是来控制代码段和数据段的指令及数据读取的地方,当然,CPU也有自己存放数据的地方,那就是通用寄存器里的数据寄存器,通常是EDX寄存器,C语言里有个register,就是把数据放在这个寄存器里,这样读取数据就相当的快了,因为不用去内存找,就省去了寻址和传送数据的时间开销。他还有一些寄存器是用来指示当前代码段的位置、数据段的位置、堆栈段的位置等等(注意这里存放的只是相应的代码或数据在内存中的地址,并不是实际的值,然后根据这个地址,通过地址总线和数据总线,去内存中获取相应的值),不然在执行代码的时候,指令和数据从哪取呢?呵呵。。。他里面还有标志寄存器,用来标识一些状态位,比如标识算术溢出呀等等。。。。。

    ————————————————————————————————————————————————————————————————

    内存分段(笔记) 


    在冯诺依曼的体系结构中必须有:代码段,堆栈段,数据段
    因为冯氏结构,本质就是取址,执行的过程


    编译器和系统在为变量分配是从高地址开始分配的.
    全局变量和函数参数在内存中的存储是由低地值到高地址的.
    函数参数为什么会放到堆区呢?
    这是因为我们的函数是在程序运行中进行动态的调用的.
    在函数的编译阶段根本无法确定他会调用几次,会需要多少内存.
    即使可以确定那时候就为变量分配好内存着实也是一种浪费。
    所以编译器为函数参数选择动态的分配..即在每次调用函数时才为它动态的进行分配空间.


    ####################################################


    内存分为4段,栈区,堆区,代码区,全局变量区

    BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
    BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

    数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

    代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。
    这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。
    在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。代码段是存放了程序代码的数据,
    假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段。

    堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,
    可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);
    当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
    栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,
    也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。
    除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
    由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。


    (1)内存分段和内存分页一样都是一种内存管理技术,分段:权限保护,分页:虚拟内存.


    (2)分段后,程序员可以定义自己的段,各段有独立的地址空间,象进程的地址空间互相独立一样.


    (3)同一个类的实例分配在一个段中,只有该类的方法可以访问,如果其他类的方法去访问,会因为段保护而出错.可以从硬件上实现类的数据保护和隐藏

    ####################################################################

    分段好处:

    cpu中的段寄存器-------段址(base)和偏移值的上限(limit)。
    段址:有效地址 中,如果有效地址大于limit,便会引发异常。这样就可以限制程序不能范围当前段外的数据,不能访问其他程序的数据。
    面向对象的好处:对象就是一块连续的内存中的数据


    寄存器是特殊形式的内存,嵌入到处理器内部。

             每个进程需要访问内存中属于自身的区域,因此,可将内存划分成小的段,按需分发给进程。
    寄存器用来存储和跟踪进程当前维护的段。偏移寄存器(Offset Registers)用来跟踪关键的数据放在段中的位置。

           在进程被载入内存中时,基本上被分裂成许多小的节(section)。我们比较关注的是6个主要的节:

    (1) .text 节

        .text 节基本上相当于二进制可执行文件的.text部分,它包含了完成程序任务的机器指令。
    该节标记为只读,如果发生写操作,会造成segmentation fault。在进程最初被加载到内存中开始,该节的大小就被固定。

    (2).data 节

    .data节用来存储初始化过的变量,如:int a =0 ; 该节的大小在运行时固定的。

    (3).bss 节

    栈下节(below stack section ,即.bss)用来存储为初始化的变量,如:int a; 该节的大小在运行时固定的。

    (4) 堆节

    堆节(heap section)用来存储动态分配的变量,位置从内存的低地址向高地址增长。内存的分配和释放通过malloc() 和 free() 函数控制。

    (5) 栈节

    栈节(stack section)用来跟踪函数调用(可能是递归的),在大多数系统上从内存的高地址向低地址增长。
    同时,栈这种增长方式,导致了缓冲区溢出的可能性。

    (6)环境/参数节

         环境/参数节(environment/arguments section)用来存储系统环境变量的一份复制文件,
    进程在运行时可能需要。例如,运行中的进程,可以通过环境变量来访问路径、shell 名称、主机名等信息。
    该节是可写的,因此在格式串(format string)和缓冲区溢出(buffer overflow)攻击中都可以使用该节。
    另外,命令行参数也保持在该区域中。


    ################################################################################

    以win32程序为例。
    程序执行时,操作系统将exe文件映射入内存。exe文件格式为头数据和各段数据组成。

    头数据说明了exe文件的属性和执行环境,段数据又分为数据段,代码段,资源段等,段的多少和位置由头数据说明。
    也就是说,不仅仅只是代码段和数据段。这些段由不同的编译环境和编译参数控制,由编译器自动生成exe的段和文件格式。
    当操作系统执行exe时,会动态建立堆栈段,它是动态的,并且属于操作系统执行环境。

    也就是说,程序在内存的映射一个为exe文件映射,包括数据段、代码段等它是不变的。
    另一个为堆栈段,它是随程序运行动态改变的。

    1、编译器把源代码转化成分立的目标代码(.o或者.obj)文件,这些文件中的代码已经是可执行的机器码或者是中间代码。
    但是其中变量等事物的地址只是一些符号。   
    2、接下来是通过链接器处理这些目标代码,主要目的就是把分立的目标代码连接成一份完整的可执行代码,
    并将其中的地址符号换成相对地址。如果这时候产生错误,我们就可以得到一份地址符号列表,而不是变量列表。   
    3、执行程序的时候操作系统分配足够的内存空间,建立好系统支撑结构后把二进制可执行代码读入内存中。
    在读入过程中内存首址就成了程序的“绝对地址”(实际上还是相对地址,不过是操作系统里的相对地址了)。
    于是绝对地址+相对地址(就是偏移量)就得到了变量的地址。   
    因此,CS的值是由系统填入的,而其它S寄存器的值则是根据程序代码中附加的信息计算后得到的
    参考链接:

    https://blog.csdn.net/YEYUANGEN/article/details/6766567 
     

    展开全文
  • 程序运行时的内存空间分布

    万次阅读 多人点赞 2014-03-21 01:33:18
    我们在写程序时,既有程序的逻辑代码,也有在程序中定义的变量等数据,那么当我们的程序进行时,我们的代码数据究竟是存放在哪里的呢?下面就来总结一下。 一、程序运行时的内存空间情况 其实在程序运行时,...
    我们在写程序时,既有程序的逻辑代码,也有在程序中定义的变量等数据,那么当我们的程序进行时,我们的代码和数据究竟是存放在哪里的呢?下面就来总结一下。
    

    一、程序运行时的内存空间情况

    其实在程序运行时,由于内存的管理方式是以页为单位的,而且程序使用的地址都是虚拟地址,当程序要使用内存时,操作系统再把虚拟地址映射到真实的物理内存的地址上。所以在程序中,以虚拟地址来看,数据或代码是一块块地存在于内存中的,通常我们称其为一个段。而且代码和数据是分开存放的,即不储存于同于一个段中,而且各种数据也是分开存放在不同的段中的。

    下面以一个简单的程序来看一下在Linux下的程序运行空间情况,代码文件名为space.c
    #include <unistd.h>
    #include <stdio.h>
    
    int main()
    {
    	printf("%d\n", getpid());
    	while(1);
    	return 0;
    }

    这个程序非常简单,输出当前进程的进程号,然后进入一个死循环,这个死循环的目的只是让程序不退出。而在Linux下有一个目录/proc/$(pid),这个目录保存了进程号为pid的进程运行时的所有信息,其中有一个文件maps,它记录了程序执行过程中的内存空间的情况。编译运行上面的代码,其运行结果如图1所示:


    从上面的图中,我们可以看到这样一个简单的程序,在执行时,需要哪些库和哪些空间。上面的图的各列的意思,不一一详述,只对重要的进行说明。
    第一列的是一个段的起始地址和结束地址,第二列这个段的权限,第三列段的段内相对偏移量,第六列是这个段所存放的内容所对应的文件。从上图可以看到我们的程序进行首先要加载系统的两个共享库,然后再加载我们写的程序的代码。

    对于第二列的权限,r:表示可读,w:表示可写,x:表示可执行,p:表示受保护(即只对本进程有效,不共享),与之相对的是s,意是就是共享。

    从上图我们可以非常形象地看到一个程序进行时的内存分布情况。下面我们将会结合上图,进行更加深入的对内存中的数据段的解说。

    二、程序运行时内存的各种数据段

    1.bss段
    该段用来存放没有被初始化或初始化为0的全局变量,因为是全局变量,所以在程序运行的整个生命周期内都存在于内存中。有趣的是这个段中的变量只占用程序运行时的内存空间,而不占用程序文件的储存空间。可以用以下程序来说明这点,文件名为bss.c
    #include <stdio.h>
    
    int bss_data[1024 * 1024];
    
    int main()
    {
    	return 0;
    }
    这个程序非常简单,定义一个4M的全局变量,然后返回。编译成可执行文件bss,并查看可执行文件的文件属性如图2所示:


    从可执行文件的大小4774B可以看出,bss数据段(4M)并不占用程序文件的储存空间,在下面的data段中,我们可以看到data段的数据是占用可执行文件的储存空间的。

    在图1中,有文件名且属性为rw-p的内存区间,就是bss段。

    2.data段
    初始化过的全局变量数据段,该段用来保存初始化了的非0的全局变量,如果全局变量初始化为0,则编译有时会出于优化的考虑,将其放在bss段中。因为也是全局变量,所以在程序运行的整个生命周期内都存在于内存中。与bss段不同的是,data段中的变量既占程序运行时的内存空间,也占程序文件的储存空间。可以用下面的程序来说明,文件名为data.c:
    #include <stdio.h>
    
    int data_data[1024 * 1024] = {1};
    
    int main()
    {
    	return 0;
    }
    这个程序与上面的bss唯一的不同就是全局变量int型数组data_data,其中第0个元素的值初始化为1,其他元素的值初始化成默认的0,而因为数组的地址是连续的,所以只要有一个元素在data段中,则其他的元素也必然在data段中。编译连接成可执行文件data,并查看可执行文件的文件属性如图3所示:


    从可执行文件的大小来看,data段数据(data_data数组的大小,4M)占用程序文件的储存空间。

    在图1中,有文件名且属性为rw-p的内存区间,就是data段,它与bss段在内存中是共用一段内存的,不同的是,bss段数据不占用文件,而data段数据占用文件储存空间。

    3.rodata段
    该段是常量数据段,用于存放常量数据,ro就是Read Only之意。但是注意并不是所有的常量都是放在常量数据段的,其特殊情况如下:
    1)有些立即数与指令编译在一起直接放在代码段(text段,下面会讲到)中。
    2)对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份。
    3)有些系统中rodata段是多个进程共享的,目的是为了提高空间的利用率。

    在图1中,有文件名的属性为r--p的内存区间就是rodata段。可见他是受保护的,只能被读取,从而提高程序的稳定性。

    4.text段
    text段就是代码段,用来存放程序的代码(如函数)和部分整数常量。它与rodata段的主要不同是,text段是可以执行的,而且不被不同的进程共享。

    在图1中,有文件名且属性为r-xp的内存区间就是text段。就如我们所知道的那样,代码段是不能被写的。

    5.stack段
    该段就是栈段,用来保存临时变量和函数参数。程序中的函数调用就是以栈的方式来实现的,通常栈是向下(即向低地址)增长的,当向栈中push一个元素,栈顶指针就会向低地址移动,当从栈中pop一个元素,栈顶指针就会向高地址移动。栈中的数据只在当前函数或下一层函数中有效,当函数返回时,这些数据自动被释放,如果继续对这些数据进行访问,将发生未知的错误。通常我们在程序中定义的不是用malloc系统函数或new出来的变量,都是存放在栈中的。例如,如下函数:
    void func()
    {
        int a = 0;
        int *n_ptr = malloc(sizeof(int));
        char *c_ptr = new char;
    }

    整型变量a,整型指针变量n_ptr和char型指针变量c_ptr,都存放在栈段中,而n_ptr和c_ptr指向的变量,由于是malloc或new出来的,所以存放在堆中。当函数func返回时,a、n_ptr、c_ptr都会被释放,但是n_ptr和c_ptr指向的内存却不会释放。因为它们是存在于堆中的数据。

    在图1中,文件名为stack的内存区间即为栈段。

    6.heap段
    heap(堆)是最自由的一种内存,它完全由程序来负责内存的管理,包括什么时候申请,什么时候释放,而且对它的使用也没有什么大小的限制。在C/C++中,用alloc系统函数和new申请的内存都存在于heap段中。

    以上面的程序为例,它向堆申请了一个int和一个char的内存,因为没有调用free或delete,所以当函数返回时,堆中的int和char变量并没有释放,造成了内存泄漏。

    由于在图1所对应的代码中没有使用alloc系统函数或new来申请内存,所以heap段并没有在图1中显示出来,所以以下面的程序来说明heap段的位置,代码文件为heap.c,代码如下:
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    int main()
    {
    	int *n_ptr = malloc(sizeof(int));
    	printf("%d\n", getpid());
    	while(1);
    	free(n_ptr);
    	return 0;
    }
    查看其运行时内存空间分布如下:


    可以看到文件名为heap的内存区间就是heap段。从上图,也可以看出,虽然我们只申请4个字节(sizeof(int))的空间,但是在操作系统中,内存是以页的方式进行管理的,所以在分配heap内存时,还是一次分配就为我们分配了一个页的内存。注:无论是图1,还是上图,都有一些没有文件名的内存区间,其实没用文件名的内存区间表示使用mmap映射的匿名空间。

    展开全文
  • 程序运行时内存的各种数据

    千次阅读 2017-11-19 21:12:18
    该段用来存放没有被初始化或初始化为0的全局变量,因为是全局变量,所以在程序运行的整个生命周期内都存在于内存中。有趣的是这个段中的变量只占用程序运行时的内存空间,而不占用程序文件的储存空间。可以用以下...
    1.bss段
    该段用来存放没有被初始化或初始化为0的全局变量,因为是全局变量,所以在程序运行的整个生命周期内都存在于内存中。有趣的是这个段中的变量只占用程序运行时的内存空间,而不占用程序文件的储存空间。可以用以下程序来说明这点,文件名为bss.c
    [cpp] view plain copy
    1. #include <stdio.h>  
    2.   
    3. int bss_data[1024 * 1024];  
    4.   
    5. int main()  
    6. {  
    7.     return 0;  
    8. }  
    这个程序非常简单,定义一个4M的全局变量,然后返回。编译成可执行文件bss,并查看可执行文件的文件属性如图2所示:


    从可执行文件的大小4774B可以看出,bss数据段(4M)并不占用程序文件的储存空间,在下面的data段中,我们可以看到data段的数据是占用可执行文件的储存空间的。

    在图1中,有文件名且属性为rw-p的内存区间,就是bss段。

    2.data段
    初始化过的全局变量数据段,该段用来保存初始化了的非0的全局变量,如果全局变量初始化为0,则编译有时会出于优化的考虑,将其放在bss段中。因为也是全局变量,所以在程序运行的整个生命周期内都存在于内存中。与bss段不同的是,data段中的变量既占程序运行时的内存空间,也占程序文件的储存空间。可以用下面的程序来说明,文件名为data.c:
    [cpp] view plain copy
    1. #include <stdio.h>  
    2.   
    3. int data_data[1024 * 1024] = {1};  
    4.   
    5. int main()  
    6. {  
    7.     return 0;  
    8. }  
    这个程序与上面的bss唯一的不同就是全局变量int型数组data_data,其中第0个元素的值初始化为1,其他元素的值初始化成默认的0,而因为数组的地址是连续的,所以只要有一个元素在data段中,则其他的元素也必然在data段中。编译连接成可执行文件data,并查看可执行文件的文件属性如图3所示:


    从可执行文件的大小来看,data段数据(data_data数组的大小,4M)占用程序文件的储存空间。

    在图1中,有文件名且属性为rw-p的内存区间,就是data段,它与bss段在内存中是共用一段内存的,不同的是,bss段数据不占用文件,而data段数据占用文件储存空间。

    3.rodata段
    该段是常量数据段,用于存放常量数据,ro就是Read Only之意。但是注意并不是所有的常量都是放在常量数据段的,其特殊情况如下:
    1)有些立即数与指令编译在一起直接放在代码段(text段,下面会讲到)中。
    2)对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份。
    3)有些系统中rodata段是多个进程共享的,目的是为了提高空间的利用率。

    在图1中,有文件名的属性为r--p的内存区间就是rodata段。可见他是受保护的,只能被读取,从而提高程序的稳定性。

    4.text段
    text段就是代码段,用来存放程序的代码(如函数)和部分整数常量。它与rodata段的主要不同是,text段是可以执行的,而且不被不同的进程共享。

    在图1中,有文件名且属性为r-xp的内存区间就是text段。就如我们所知道的那样,代码段是不能被写的。

    5.stack段
    该段就是栈段,用来保存临时变量和函数参数。程序中的函数调用就是以栈的方式来实现的,通常栈是向下(即向低地址)增长的,当向栈中push一个元素,栈顶指针就会向低地址移动,当从栈中pop一个元素,栈顶指针就会向高地址移动。栈中的数据只在当前函数或下一层函数中有效,当函数返回时,这些数据自动被释放,如果继续对这些数据进行访问,将发生未知的错误。通常我们在程序中定义的不是用malloc系统函数或new出来的变量,都是存放在栈中的。例如,如下函数:
    [cpp] view plain copy
    1. void func()  
    2. {  
    3.     int a = 0;  
    4.     int *n_ptr = malloc(sizeof(int));  
    5.     char *c_ptr = new char;  
    6. }  

    整型变量a,整型指针变量n_ptr和char型指针变量c_ptr,都存放在栈段中,而n_ptr和c_ptr指向的变量,由于是malloc或new出来的,所以存放在堆中。当函数func返回时,a、n_ptr、c_ptr都会被释放,但是n_ptr和c_ptr指向的内存却不会释放。因为它们是存在于堆中的数据。

    在图1中,文件名为stack的内存区间即为栈段。

    6.heap段
    heap(堆)是最自由的一种内存,它完全由程序来负责内存的管理,包括什么时候申请,什么时候释放,而且对它的使用也没有什么大小的限制。在C/C++中,用alloc系统函数和new申请的内存都存在于heap段中。

    以上面的程序为例,它向堆申请了一个int和一个char的内存,因为没有调用free或delete,所以当函数返回时,堆中的int和char变量并没有释放,造成了内存泄漏。

    由于在图1所对应的代码中没有使用alloc系统函数或new来申请内存,所以heap段并没有在图1中显示出来,所以以下面的程序来说明heap段的位置,代码文件为heap.c,代码如下:
    [cpp] view plain copy
    1. #include <unistd.h>  
    2. #include <stdlib.h>  
    3. #include <stdio.h>  
    4.   
    5. int main()  
    6. {  
    7.     int *n_ptr = malloc(sizeof(int));  
    8.     printf("%d\n", getpid());  
    9.     while(1);  
    10.     free(n_ptr);  
    11.     return 0;  
    12. }  
    查看其运行时内存空间分布如下:


    可以看到文件名为heap的内存区间就是heap段。从上图,也可以看出,虽然我们只申请4个字节(sizeof(int))的空间,但是在操作系统中,内存是以页的方式进行管理的,所以在分配heap内存时,还是一次分配就为我们分配了一个页的内存。注:无论是图1,还是上图,都有一些没有文件名的内存区间,其实没用文件名的内存区间表示使用mmap映射的匿名空间。
    展开全文
  • Java 内存区域-运行时数据区域

    千次阅读 2018-08-19 20:46:08
    一开始看的比较快,对JVM 运行时数据区域只有一个模糊的概念,不太清楚不同内存区域里面到底存放了那些数据,所以在此记录。   我们都知道Java 与C、C++ 最大的区别就是内存管理领域(Java 有内存动态分配和垃圾...
  • C++程序内存结构

    千次阅读 2016-07-19 15:56:08
    栈区(stack):编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构的栈。 堆区(heap):一般是由程序员分配释放,若程序员不释放的话,程序结束时可能由OS回收,值得注意的是他与...
  • 在C++中,有内存分成6个区,即系统数据区,自由存储区,文本区(程序代码段),const数据区,全局/静态区,堆区和栈区。  系统数据区:存放的是系统数据,我们是不能自由访问的,时候windows系统会突然弹出一个...
  • 对任何一个普通进程来讲,它都会涉及到5种不同的数据段。归纳一下进程对应的内存空间中所包含的5种不同的数据区都是干什么的。...数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的...
  • 数据类型 【知识点】 数据类型 整型 字符型 实数(浮点型)型 【内容】 一、数据类型 ...C语言要求在定义所有的变量时都要指定变量的类型。...在数学中,数值是不分...而在计算机中,数据存放在存储单元中的,它是...
  • 程序内存结构BSS段数据代码段栈区堆区 一个程序本质上都是由BSS段、数据段、代码段三个组成的。可以看到一个可执行程序在存储(没有调入内存)时分为代码段、数据区和未初始化数据区三部分。 BSS段 BSS段(未...
  • 如何深入理解Lua数据结构和内存占用? ** 导语 Lua底层数据结构的内存动态分配,一般情况下不太好估算内存占用。腾讯游戏学院专家Ross在本文剖析lua常见数据结构string和table的底层实现原理,并从中找到一般性的...
  • 我们在写程序时,既有程序的逻辑代码,也有在程序中定义的变量等数据,那么当我们的程序进行时,我们的代码数据究竟是存放在哪里的呢?下面就来总结一下。 一、程序运行时的内存空间情况 其实在程序...
  • 对于Java开发人员来讲,在虚拟机自动内存管理机制的帮助下,不需要为每一个new操作去写配对的delete/free代码, 不容易出现内存泄露和内存溢出的问题。 正是因为JVM管理内存控制的权利,一旦出现内存泄露和内存溢出...
  • 12.程序运行为啥需要内存

    千次阅读 2016-03-13 10:50:02
    12.1.计算机程序的本质 12.2.冯诺依曼结构和哈佛结构 12.3.为啥需要内存 12.4.操作系统如何管理内存 12.5.编程语言如何管理内存
  • 程序内存中的分布

    千次阅读 2015-07-23 17:35:50
    BSS段:(bsssegment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStarted by Symbol的简称。BSS段属于静态内存分配。 数据段 :数据段(datasegment)通常是指用来存放程序中 已初始...
  • 没有内存,怎么还能跑程序

    万次阅读 多人点赞 2020-02-26 10:33:00
    正如帕金森定律说的那样:不管存储器多大,但是程序大小的增长速度比内存容量的增长速度要快的多。下面我们就来探讨一下操作系统是如何创建内存并管理他们的。 经过多年的探讨,人们提出了一种 分层存储器体系...
  • 数据内存中的存储

    千次阅读 2018-07-13 16:27:51
    数据内存中的存储首先认识一下计算机存储结构:寄存器:中央处理器CPU的一部分,空间比较小在kb级别,用来暂存指令,数据和地址。CPU在处理数据时往往先把数据取存到寄存器中,然后再做处理,这样可以加快直接从...
  • 1.1.程序运行为什么需要内存

    千次阅读 2016-04-24 17:49:20
    程序运行的过程就是电脑在不断地进行计算,在计算过程中需要各种数据(也就是变量),程序运行需要数据(变量)和代码共同支持,代码就是函数,它负责指令,在执行这些指令的过程中就需要产生一些数据(变量)。...
  • C/C++程序内存的分配

    万次阅读 多人点赞 2018-08-13 12:43:57
    一、一个C/C++编译的程序占用内存分为以下几个部分: 栈区(stack):由编译器自动分配与释放,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等。其操作类似于数据结构中的栈。 堆区(heap):...
  • 由本人归纳整理,但大部分内容来自于百度文库中的一篇文章,在此对原作者(姓名不详)表示衷心感谢!...由于大部分字面常量属于只读数据,因此文字常量区常被归入程序代码区。如: int i= 50; char*p
  • 在上篇文章中,我们了解到 JVM 运行时数据五个区域,分别是:程序计数器、Java 虚拟机栈、本地方法栈、Java 堆、方法区。在这篇文章中,我们就来了解下程序计数器与 Java 虚拟机栈和本地方法栈。 程序计数器 ...
  • OpenCV程序内存泄露的预防与检测

    千次阅读 2014-01-01 17:23:13
    I. 内存泄露  首先我们要搞清楚什么是内存泄露。一个应用程序在运行时占用内存区域可以分为...堆(Heap)区和自由存储区存放我们程序运行过程中动态分配的内存,主要由C语言的malloc函数和C++的new运算符进行分配(Open
  • 事实上在JVM中是用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。 一、运行时数据区域包括哪些? 根据《Ja
  • 深入理解Java虚拟机-Java内存区域与内存溢出异常

    万次阅读 多人点赞 2020-01-03 21:42:24
    文章目录概述运行时数据区域程序计数器(线程私有)Java虚拟机栈(线程私有)局部变量表操作数栈动态链接方法返回地址小结本地方法栈(线程私有)Java堆(全局共享)方法区(全局共享)运行时常量池直接内存HotSpot...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 114,946
精华内容 45,978
关键字:

内存存放的既有程序代码又有数据