在《虚拟地址空间以及编译模式》一节中讲到,虚拟地址空间在32位环境下的大小为 4GB,在64位环境下的大小为 256TB,那么,一个C语言程序的内存在整个地址空间中是如何分布的呢?数据在哪里?代码在哪里?为什么要这样分布?这些就是本节要讲解的内容。

程序内存在地址空间中的分布情况称为内存模型(Memory Model)。内存模型由操作系统构建,在Linux和Windows下有所差异,并且会受到编译模式的影响,本节我们讲解Linux下32位环境和64位环境的内存模型。

内核空间和用户空间

对于32位环境,理论上程序可以拥有 4GB 的虚拟地址空间,我们在C语言中使用到的变量、函数、字符串等都会对应内存中的一块区域。

但是,在这 4GB 的地址空间中,要拿出一部分给操作系统内核使用,应用程序无法直接访问这一段内存,这一部分内存地址被称为内核空间(Kernel Space)。

Windows 在默认情况下会将高地址的 2GB 空间分配给内核(也可以配置为1GB),而 Linux 默认情况下会将高地址的 1GB 空间分配给内核。也就是说,应用程序只能使用剩下的 2GB 或 3GB 的地址空间,称为用户空间(User Space)。

Linux下32位环境的用户空间内存分布情况

我们暂时不关心内核空间的内存分布情况,下图是Linux下32位环境的一种经典内存模型:

对各个内存分区的说明:

内存分区 说明
程序代码区
(code)
存放函数体的二进制代码。一个C语言程序由多个函数构成,C语言程序的执行就是函数之间的相互调用。
常量区
(constant)
存放一般的常量、字符串常量等。这块内存只有读取权限,没有写入权限,因此它们的值在程序运行期间不能改变。
全局数据区
(global data)
存放全局变量、静态变量等。这块内存有读写权限,因此它们的值在程序运行期间可以任意改变。
堆区
(heap)
一般由程序员分配和释放,若程序员不释放,程序运行结束时由操作系统回收。malloc()calloc()free() 等函数操作的就是这块内存,这也是本章要讲解的重点。

注意:这里所说的堆区与数据结构中的堆不是一个概念,堆区的分配方式倒是类似于链表。
动态链接库 用于在程序运行期间加载和卸载动态链接库。
栈区
(stack)
存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。

在这些内存分区中(暂时不讨论动态链接库),程序代码区用来保存指令,常量区、全局数据区、堆、栈都用来保存数据。对内存的研究,重点是对数据分区的研究。

程序代码区、常量区、全局数据区在程序加载到内存后就分配好了,并且在程序运行期间一直存在,不能销毁也不能增加(大小已被固定),只能等到程序运行结束后由操作系统收回,所以全局变量、字符串常量等在程序的任何地方都能访问,因为它们的内存一直都在。

常量区和全局数据区有时也被合称为静态数据区,意思是这段内存专门用来保存数据,在程序运行期间一直存在。

函数被调用时,会将参数、局部变量、返回地址等与函数相关的信息压入栈中,函数执行结束后,这些信息都将被销毁。所以局部变量、参数只在当前函数中有效,不能传递到函数外部,因为它们的内存不在了。

常量区、全局数据区、栈上的内存由系统自动分配和释放,不能由程序员控制。程序员唯一能控制的内存区域就是堆(Heap):它是一块巨大的内存空间,常常占据整个虚拟空间的绝大部分,在这片空间中,程序可以申请一块内存,并自由地使用(放入任何数据)。堆内存在程序主动释放之前会一直存在,不随函数的结束而失效。在函数内部产生的数据只要放到堆中,就可以在函数外部使用。

Linux下C语言程序的内存布局的更多相关文章

  1. linux下C/C++程序的内存布局

    内核空间和用户空间: 我们在编写程序时使用的内存空间叫虚拟内存,程序在运行时,要完成虚拟内存到物理内存的转换.假如在32位环境上,理论上我们可以使用的虚拟内存空间是4GB,但实际上这4GB并不能完全给 ...

  2. C语言程序的内存布局

    C语言程序的内存布局 一:C语言程序的存储区域 C语言编写的程序经过编绎-链接后,将形成一个统一的文件,它由几个部分组成,在程序运行时又会产生几个其他部分,各个部分代表了不同的存储区域: 1.代码段( ...

  3. linux下C语言实现的内存池【转】

    转自:http://blog.chinaunix.net/uid-28458801-id-4254501.html 操作系统:ubuntu10.04 前言:     在通信过程中,无法知道将会接收到的 ...

  4. Anatomy of a Program in Memory.剖析程序的内存布局

    原文标题:Anatomy of a Program in Memory 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩文章翻译 ...

  5. linux 下C语言学习路线

    UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...

  6. Unix和Linux下C语言学习指南

    转自:http://www.linuxdiyf.com/viewarticle.php?id=174074 Unix和Linux下C语言学习指南 引言 尽管 C 语言问世已近 30 年,但它的魅力仍未 ...

  7. 笔记整理——Linux下C语言正则表达式

    Linux下C语言正则表达式使用详解 - Google Chrome (2013/5/2 16:40:37) Linux下C语言正则表达式使用详解 2012年6月6日Neal627 views发表评论 ...

  8. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  9. Linux下C语言编程基础学习记录

    VIM的基本使用  LINUX下C语言编程 用gcc命令编译运行C语言文件 预处理阶段:将*.c文件转化为*.i预处理过的C程序. 编译阶段:将*.i文件编译为汇编代码*.s文件. 汇编阶段:将*.s ...

  10. Linux下的 sniff-andthen-spoof程序编写

    Linux下的 sniff-andthen-spoof程序编写 一.任务描述 在本任务中,您将结合嗅探和欺骗技术来实现以下嗅探然后欺骗程序.你需要两台机器在同一个局域网.从机器A ping IP_X, ...

随机推荐

  1. python面向对象--类的刨析

    编程日常::::#编程就是程序员用特定的语法加数据结构加算法在计算机上执行过程,方式有很多种,最常用的就是面向对象编程和面向过程编程#设计思路一开始解决一个大问题,然后把大问题分解成小问题,一步步解决 ...

  2. SQLSERVER 存储过程里 执行sql字符串 并返回结果

    -- Author: <Author,,Name>-- Create date: <Create Date,,>-- Description: 停用/启用12个月销售目标--e ...

  3. Day21 21.2:CrawlSpider-redis分布式爬虫

    CrawlSpider-redis分布式 分布式在日常开发中并不常用,只是一个噱头! 概念: 可以使用多台电脑搭建一个分布式机群,使得多台对电脑可以对同一个网站的数据进行联合且分布的数据爬取. 声明: ...

  4. chrome浏览器启用es6语法支持,初次体验浏览器端模块化加载

    医院项目,记录下,花了一个晚上的时间. 注意:最新版本的chrome浏览器已支持module语法,需要在web服务器环境下运行! 注:chrome76版本及以上不再需要设置了,浏览器已默认支持,至于从 ...

  5. MySQL 常用命令(1)------连接、添加用户与授权

    一.连接MySQL 格式: mysql -h主机地址 -u用户名 -p用户密码 1.连接到本机上的MYSQL 进入目录mysql\bin,再键入命令mysql -u root -p,回车后提示你输密码 ...

  6. 把一个元器件的原理图分成多个Part-转载

    (24条消息) [AD20]把一个元器件的原理图分成多个Part_不知道在干嘛每天的博客-CSDN博客_ad中原理图怎么分成几部分 以LM358芯片为例:把LM358原理图的A和B分开画,分成A和B两 ...

  7. 实现MybatisPlus乐观锁

    1.实体类中添加version字段及相关注解 @Version@TableField(fill = FieldFill.INSERT)//第一次添加数据时使其有个默认值1private Integer ...

  8. mysql数据库常用指令

    1.查询当前连接数据库别名 select database(); Current database 项显示当前连接的数据库 2.查询数据表中当天的数据 select * from 表名 WHERE T ...

  9. Docker学习——Docker 三剑客(七)

    Docker Compose 简介 Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责arg>...] [options] [COMMAND] ...

  10. SpringBoot怎么管理封装java包的关系

    首先SpringBoot直接写注解加依赖就可以了,基本上不用写xml,非常方便,在这里我只写了两个核心包 为什么选择jar类型? SpringBoot基本上是个应用程序了,只要用java命令程序去运行 ...