C/C++中的内存分区

五大内存分区

在C++中,内存分成5个区,它们分别是:栈、堆、自由存储区、全局/静态存储区和常量存储区。

栈:由编译器自动分配和释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。

堆:堆由程序员手动分配和释放,且完全不同于数据结构中的堆,分配方式类似链表。由new/delete 申请和释放。若程序员忘记释放则由系统于程序结束时回收。

自由存储区:是由malloc等分配的内存块,和堆十分相似,不过是用free来释放。

全局/静态存储区:存放全局变量和静态变量。在C中,全局变量又分为初始化(DATA段)的和未初始化(BSS段)的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域;C++中没有这一区分。

常量存储区:这是一块特殊存储区,里面存放常量,不允许修改。

BSS段、DATA段、CODE段

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

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

CODE段(code segment):通常是用来存放程序执行代码的一块内存区域,这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的函数变量,例如字符串常量等。

Linux环境程序典型的内存布局如下图所示:

代码段(Text Segment):用户存放CPU执行的机器指令,为防止指令被其它程序修改,代码段一般只读不可更改。比如,源码中的字符串常量存储于代码段,不可修改。

初始化数据段(Data Segment):又称为DATA段,用于存储初始化的全局变量和Static变量,段大小在编译时确定,所以内存的分配属于静态内存分配。

未初始化数据段(BSS Segment,Block Started by Symbol):又称为BSS段,通常用来存放程序中未初始化的全局变量和Static,虽未显示初始化,但在程序载入内存执行时,由内核清0,所以未显示初始化则默认为0。BSS段的大小也是在编译时确定,运行时内存的分配属于静态内存分配。

堆(Heap):用于保存程序运行时动态申请的内存空间,由开发人员手动申请,手动释放,若不手动释放,程序结束后由系统回收,生命周期是整个程序运行期间,比如使用malloc()或new申请的内存空间。堆的地址空间“向上增加”,即当堆上保存的数据越多,堆的地址就越高。堆的内存分配属于动态分配,一般运行时才知道分配的内存大小,并且堆可分配存活于函数之外的内存,在未显示调用free()或delete释放时,其生命周期为进程的生命周期。

映射段(Memory Mapping Segment):该区域内核将文件内容直接映射到内存。任何应用程序都可以请求该区域。Linux中通过mmap()系统调用,Windows中通过creatFileMapping()/MapViewOfFile()创建。文件I/O时内存映射方便并且高效,所以,它常用来加载动态库,还可以创建一种匿名映射,并不对应于文件,而用于程序数据。在Linux中,如果使用malloc()申请一块过大的内存,C库函数便会创建这种内存映射段,而不是使用堆内存。“过大”的内存指超过M_MMAP_THRESHOLD字节,默认128KB,可以通过mallopt()函数调整。映射段也属于动态分配。

栈(Stack):用于保存函数的局部变量(但不包括static声明的静态变量,静态变量存放在数据段或BSS段)、参数、返回值、函数返回地址以及调用者环境信息(比如寄存器值)等信息,由系统进行内存的管理,在函数完成执行后,系统自行释放栈区内存,不需要用户管理。整个程序的栈区的大小可以由用户自行设定,Windows默认的栈区大小为1M,可通过Visual Studio更改编译参数手动更改栈的大小。64bits的Linux默认栈大小为10MB,可通过命令ulimit -s临时修改。栈是一种“后进先出”(Last In First Out,LIFO)的数据结构,这意味着最后入栈的数据,将会是第一个出栈的数据。对于那些暂时存贮无需长期保存的信息来说,LIFO这种数据结构非常理想。在调用函数后,系统通常会清除栈上保存的信息。栈另外一个重要的特征是,它的地址空间“向下减少”,即当栈上保存的数据越多,栈的地址就越低。

内核空间(Kernel Space),:用于存储操作系统和驱动程序,用户空间用于存储用户的应用程序,二者不能简单地使用指针传递数据。当一个进程执行系统调用而陷入内核空间执行内核代码时,我们称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态),即此时处理器在执行最低特权级(3级)用户代码中。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。

内存段的特点和区别如下。

|段名|存储内容    |分配方式|生长方向|读写特点|运行态|

|—|---|—|---|—|

|代码段|程序指令、字符串常量、虚函数表|静态分配|由低到高|只读|用户态|

|数据段|初始化的全局变量和静态变量|静态分配|由低到高|可读可写|用户态|

|BSS段|未初始化的全局变量和静态变量|静态分配|由低到高|可读可写|用户态|

|堆|动态申请的数据|动态分配|由低到高|可读可写|用户态|

|映射段|动态链接库、共享文件、匿名映射对象|动态分配|由低到高|可读可写|用户态|

|栈|局部变量、函数参数与返回值、函数返回地址、调用者环境信息|静态分配|由高到低|可读可写|用户态|

|内核空间|储操作系统、驱动程序|动态+静态|由低到高+由高到低|不能直接访问|内核态|

关于内核空间,其中包含内核栈和内核的数据段,所以内存地址生长方向既有由低到高(内核数据段),也有由高到低(内核栈)。关于读写的特点,由内核进行读写,用户程序不可直接访问。

以下面的C++代码为例,看一下常见变量所属的内存段。

#include <string.h>

int a = 0;                         // a在数据段,0为文字常量,在代码段
char *p1;                          // BSS段,系统默认初始化为NULL
void main()
{
    int b;                         //栈
    char *p2 = "123456";          //123456在代码段,p2在栈上
    static int c =0;              //c在数据段
    const int d=0;                 //栈
    static const int d;            //数据段
    p1 = (char*)malloc(10);        //分配得的10字节在堆
    strcpy(p1,"123456");         //123456放在字符串常量区,编译器可能会将它与p2所指向的"123456"优化成一个地方
}

参考文献

https://blog.csdn.net/K346K346/article/details/45592329

原文地址:https://www.cnblogs.com/ovs98/p/9902118.html

时间: 2024-10-12 15:17:25

C/C++中的内存分区的相关文章

程序中五大内存分区

本文介绍C/C++中堆,栈及静态数据区. 五大内存分区 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区.下面分别来介绍: 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等. 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收. 自由存储区,就是那些由malloc等分

Cocoa框架中的内存分区

NSObject对象类实例为我们提供了两种分配内存的方式:alloc和allocWithZone:.alloc的实现也是为了调用allocWitZone:,它传入了一个默认的zone.所以明确的说,NSObject提供了一种分配内存的方式.什么是zone?为什么要使用zone? Zone代表了内存中的一段连续的内存区域.当我们需要创建一些具有相同访问模式以及生命周期的对象时,我们可以采用Zone让这些对象在计算机的地址空间中保持相邻的位置,这样可以提高应用程序的性能.要搞清楚对象在内存中的位置如

JVM中的内存分区简介

1.JVM的内存区域划分: 大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) ,   VM Stack(虚拟机栈,也有翻译           成 JAVA 方法栈的),Native Method Stack  ( 本地方法栈 ),其中Method Area 和  Heap 是线程共享的(方法区和堆),其他的几个(VM Stack,Native Method        

操作系统中的内存分区

c++有三个地方存放对象:栈.堆.全局数据区.常量区.代码区 栈:本地变量 堆:只有new出来的对象 全局数据区:未初始化的全局变量.静态本地变量.静态成员变量 常量区:存储已经初始化的全局变量.静态本地变量.静态成员变量 原文地址:https://www.cnblogs.com/go-ahead-wsg/p/12180778.html

iOS 中内存分区

1  关于RAM ROM 我们知道,内存为RAM类型不具备掉电存储能力(即一掉电数据全没了),所以app程序一般存放于内存卡(Flash)或ROM中.RAM的访问速度要远高内存卡(Flash)或ROM. 2  当启动一个app 为了加快程序执行速度,系统会把开启的那个app程序从Flash或ROM里面拷贝到内存(RAM),然后从内存里面执行代码.另一个原因是CPU不能直接从内存卡里面读取指令(需要Flash驱动等等). 3  内存分区:可以分为5个区 1).栈区(stack)— 这个一般由编译器

iOS开发中的内存分配与分区

iOS开发中的内存分配与分区 关于RAM&ROM RAM与ROM就是具体的存储空间,统称为存储器. RAM(random access memory):运行内存,CPU可以直接访问,读写速度非常快,但是不能掉电存储.它又分为: 动态DRAM,速度慢一点,需要定期的刷新(充电),我们常说的内存条就是指它,价格会稍低一点,手机中的运行内存也是指它. 静态SRAM,速度快,我们常说的一级缓存,二级缓存就是指它,当然价格高一点. ROM(read only memory):存储性内存,可以掉电存储,例如

管理系统中的简单分区和文件系统

管理系统中的简单分区和文件系统 一.简单分区和文件系统 存储是每个计算机系统的基本需求. Red Hat Enterprise Linux 提供了一些强大的工具 , 它们能在大量的场景中管理多种类型的存储设备 disk 是用于管理磁盘分区的实用程序.您可以通过选择 -l选项和指定磁盘名称 ( fdisk -cul /dev/vda ) 运行该实用程序 , 以查看磁盘及其分区.您可以通过交互式地运行该实用 程序 , 并选择相应的菜单选项 ( fdisk -cu /dev/vda ) 进行更改. -

c语言学习之基础知识点介绍(十八):几个修饰关键字和内存分区

一.几个修饰关键字 全局变量: 全局变量跟函数一样也分为声明和实现.如果是全局变量,实现在它调用之后,那么需要在调用之前进行声明.注意:全局变量的声明只能写在函数外,写在函数就不是全局变量了而是局部变量. static: 修饰局部变量:      可以把局部变量变为静态变量.意思就是:程序一启动就加载,程序退出才会回收空间(跟全局变量很像) .   静态变量:用static修饰的局部变量就叫静态变量. 修饰全局变量:            让全局变量只能在本模块中访问.     修饰函数:   

C++:程序分段与内存分区

1. 进程分段 bss段(bss segment):存放未初始化(或者说是zero-initialization,详见C/C++对象初始化相关)的全局对象,属于静态内存分配.(bss全称为"Block Started by Symbol") data段(data segment):存放已经初始化的全局对象,属于静态内存分配. 栈(stack):存放函数内创建的局部对象(static对象属于全局对象),主要属于静态内存分配,C的alloca函数也用于支持动态内存分配. 堆(heap):存