摘要:本文主要讲述了Linux系统中。程序存储结构(代码区、数据段和BBS区)与进程的基本结构(代码区、数据段、BBS区、堆和栈)。以及堆和栈的差别.

Linux程序存储结构与进程结构

1.Linux程序存储结构

在Linux系统下,程序是一个普通的可运行文件,图1是一个Linux下ELF格式可运行文件的基本情况.

 
图1 ELF格式可运行文件的基本信息

能够看出,此ELF格式可运行文件在存储时,没有调入到内存,分为代码区(text),数据区(data)和为初始化区(bss)3个部分.各段基本说明例如以下:

(1)代码区(text segment).也称正文段.存放CPU可运行的机器指令。通常代码区是可共享的(即另外的运行代码能够訪问调用它)代码区一般是仅仅读的。使其仅仅读的原因是防止程序意外地改动了它的指令.因此,常量数据在编译时在代码段中分配空间.样例1会说明这点.

   代码区的指令包括操作码和操作对象(或对象的地址引用)。假设是详细数值。将直接包括在代码中.假设是局部数据,将在执行时在栈区分配空间。然后再引用数据的地址。假设是BBS区和数据区,在代码中相同将引用该数据的地址.

(2)全局初始化数据区/静态数据区。或简称数据段.该区包括了在程序中明白被初始化的全局变量、已经初始化的静态变量(包括全局静态变量和局部静态变量).但被const声明的变量以及字符串常量在代码段中申请空间.

(3)未初始化数据区,也称BBS区.存入的是未初始化全局变量和未初始化静态变量.BBS区的数据在程序開始运行之前被内核初始化为0或者空指针(NULL).

样例1。说明常量数据在编译时在代码段中分配空间.

#include <stdio.h>
int main()
{
char *buf =NULL;
printf("%s\n",buf);
return 0;
}

编译后检測各段的大小:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDAwNjEwMg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" height="88" width="592">

在代码中加入一个字符常量和const数据常量:

#include <stdio.h>
const int i=10;
int main()
{
char *buf = NULL;
printf("%s\n",buf);
return 0;
}

又一次编译后查看:代码段的数据添加了4字节的const i.

2.Linux进程结构

在Linux系统下,假设将一个ELF格式可执行文件载入到内存中执行。则将演变成一个或多个进程.进程是Linux事务的基本管理单元,全部的进程均拥有自己的独立的环境和资源.进程的环境由当前系统状态及其父进程信息决定和组成.

   一个正在执行的进程在内存空间中申请的代码区、初始化数据区、未初始化数据区、上下文信息以及挂载的信号等等.

(1)代码区.载入的是可运行文件的代码段。其载入到内存中的位置由载入器完毕.

(2)全局初始化数据区/静态数据区.载入的是可执行文件数据段。位置可位于代码段后也能够分开.程序在执行之初就为该数据段申请了空间,在程序退出时才释放,因此。存储于数据段的数据的生存周期为整个程序执行过程.

(3)未初始化数据区.载入的是可执行文件BBS段,位置能够分开也能够紧靠数据段.程序在执行之初为该部分申请了空间。在程序退出时才释放,存储于该部分的数据的生存周期为整个程序执行过程.

(4)栈.由编译器自己主动分配释放.自己主动变量以及每次函数调用所须要保存的信息都存放在此段中.每次调用函数时,其返回地址以及调用者的环境信息都存放在栈中.然后,近期被调用的函数在栈上为其自己主动和暂时变量分配存储空间.通过这样的方式使用栈。能够递归的调用C函数.递归函数每次调用自身时,就使用一个新的栈帧,因此一个函数调用实例中的变量集不会影响还有一个函数调用实例中的变量.

(5)堆,通常在堆中进行动态存储分配.一般由程序猿分配和释放,若程序猿不释放,程序结束是由系统收回.堆位于非初始化数据段和栈之间.

    图2 所看到的为ELF格式可运行文件存储结构和Linux进程基本结构的对比图.


图2 可运行文件与进程存储布局

3.为什么分这么多个区?

(1)代码段和数据段分开。执行时便于分开载入,在哈佛体系结构的处理器将取得更好的流水线处理效率.

(2)代码是依次执行,由处理器的PC指针依次读入,并且代码能够被多个程序共享,数据在整个执行过程中有可能多次被使用。假设将代码和数据混合在一起将造成空间的浪费.

(3)暂时数据及须要再次使用的代码在执行时放入栈中,生命周期短,便于提高资源利用率.

(4)堆区能够由程序猿分配和释放,以便用户自由分配。提高程序的灵活性.

4.堆和栈的差别

栈是由编译器在程序执行时分配的空间。由操作系统维护.堆是由malloc()函数分配的内存块,内存的管理由程序猿手动控制,在C语言使用free()函数完毕.主要差别有一下几点:

(1)管理方式不同

    程序在执行时栈由操作系统自己主动管理,无须程序猿手工控制。而堆空间的申请、释放工作由程序猿控制,easy产生内存泄露.

(2)空间大小不同

    栈是向低地址扩展,是一块连续的内存区域.即栈顶的地址和栈的最大容量是系统预先规定好的,当申请的空间超过栈的剩余空间时,将出现栈溢出错误.堆是向高地址扩展,是不连续的内存区域.由于系统是用链表来存储空暇内存地址的。且链表的遍历方向是由低地址高地址.

(3)产生碎片不同

    对于堆来说。频繁的malloc/free势必会造成内存空间的不连续从而造成大量的碎片,使程序效率减少.对于栈来说。一定是连续的物理内存空间.

(4)增长方式不同

    在X86平台上,堆的增长方向是向上。即向着内存地址添加的方向。栈的增长方向是向下的,即向着内存地址减小的方向.

(5)分配方式不同

    堆都是程序中由malloc()函数动态申请分配并由free() 函数释放。栈的分配和释放是由操作系统完毕的,栈的动态分配有alloca()函数完毕,可是栈的动态分配和堆是不同的,其由编译器进行分配和释放,无须手工完毕.

(6)分配效率不同

    栈是系统提供的。操作系统会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都是专门的指令运行.堆则是C函数库提供的,它的机制非常复杂。比如为了分配一块内存,则须要操作系统又一次整理内存。搜索整理内存空间,这样就有机会分到足够大小的内存,然后返回.显然。堆的效率比栈要低的多.

笔者:个人能力有限,仅仅是学习參考...读者若发现文中错误,敬请提出.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台。静下心来。慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Linux程序存储结构与进程结构 堆和栈的差别的更多相关文章

  1. Linux程序存储结构与进程结构堆和栈的区别【转】

    转自:http://www.hongkevip.com/caozuoxitong/Unix_Linux/24581.html 红客VIP(http://www.hongkevip.com):Linux ...

  2. 第二十一篇:Linux 操作系统中的进程结构

    前言 在 Linux 中,一个正在执行的程序往往由各种各样的进程组成,这些进程除了父子关系,还有其他的关系.依赖于这些关系,所有进程构成一个整体,给用户提供完整的服务( 考虑到了终端,即与用户的交互 ...

  3. Linux 操作系统中的进程结构

    前言 在 Linux 中,一个正在执行的程序往往由各种各样的进程组成,这些进程除了父子关系,还有其他的关系.依赖于这些关系,所有进程构成一个整体,给用户提供完整的服务( 考虑到了终端,即与用户的交互 ...

  4. java进程/线程;堆和栈;多线程

    一.进程和线程 进程:在内存中运行的应用程序,一个exe是一个进程. 如:ps -exf  可以查看各个应用的进程,其中ppid为父进程: ps aux | egrep '(cron|syslog)' ...

  5. linux面试之--堆、栈、自由存储区、全局/静态存储区和常量存储区

    栈,就是那些由编译器在须要的时候分配,在不须要的时候自己主动清除的变量的存储区.里面的变量一般是局部变量.函数參数等.在一个进程中.位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用.和堆 ...

  6. Java中对象、对象引用、堆、栈、值传递以及引用传递的详解

    Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...

  7. Linux进程调度与源码分析(二)——进程生命周期与task_struct进程结构体

    1.进程生命周期 Linux操作系统属于多任务操作系统,系统中的每个进程能够分时复用CPU时间片,通过有效的进程调度策略实现多任务并行执行.而进程在被CPU调度运行,等待CPU资源分配以及等待外部事件 ...

  8. Linux中表示“时间”的结构体和相关函数

    转载于:http://blog.chinaunix.net/uid-25909722-id-2827364.html      Linux中表示“时间”的结构体和相关函数 2011-09-13 17: ...

  9. Linux文件系统的主要目录结构说明及分区方案

    Linux操作系统有一些固定的目录.各种Linux发行版的目录结构虽然不会一模一样,但是不会有很大差异.知道了这些目录的作用,不仅对你进行磁盘分区规划很有帮助,而且会让你以后的日常维护工作变得轻松.只 ...

随机推荐

  1. 通过邮箱验证注册——.net代码

    在写一些面向用户的网站类的程序时,必不可少的一个就是注册,通常情况下,我们会选择邮箱验证后注册,或者手机发送验证码注册.上篇文章中已经简单的描述了手机验证注册,这篇主要介绍一下邮箱验证. 邮箱验证的步 ...

  2. [BZOJ4859][BJOI2017]机动训练(DP)

    4859: [BeiJing2017]机动训练 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 105  Solved: 63[Submit][Stat ...

  3. [SRM478]RandomApple

    题意:有$k$种苹果和$n$个箱子,每个箱子中有一些苹果,先等概率选取$n$个箱子组成集合的非空子集,再从选出的苹果中随机选一个,问每种苹果被选中的概率是多少 设箱子$i$有$cnt_{i,j}$个第 ...

  4. 【动态规划】mr354-坐车看球

    [题目大意] 两个球队的支持者要一起坐车去看球,他们已经排成了一列.我们要让他们分乘若干辆巴士,同一辆巴士上的人必须在队伍中是连续的.为了在车上不起冲突,希望两队的支持者人数尽量相等,差至多是D.有一 ...

  5. ubuntu16 安装docker

    本文开发环境为Ubuntu 16.04 LTS 64位系统,通过apt的docker官方源安装最新的Docker CE(Community Edition),即Docker社区版,是开发人员和小型团队 ...

  6. Problem E: 零起点学算法97——进制转换

    #include<stdio.h> int main(){ ]; while(scanf("%d%d",&n,&r)!=EOF){ ,i=; ){ fl ...

  7. Java 8:不要再用循环了 Stream替代for循环

    原文:http://www.importnew.com/14841.html 在这篇文章里,我们将会去了解传统循环的一些替代方案.在Java 8的新功能特性中,最棒的特性就是允许我们去表达我们想要完成 ...

  8. Android 卡顿优化 4 布局优化实际技巧

    今天分享一些layout布局书写中的一些技巧,希望看过之后你也一样可以写出性价比高的布局.我个人的目标是用最少的View写出一样效果的布局.因为我相信View的数量减少伴随着的就是层级的减少.从而达到 ...

  9. websocket+golang聊天室

    原文地址: http://www.niu12.com/article/3 websocket+golang聊天室 main.go和index.html放在同一目录下 main.go package m ...

  10. Anaconda安装Graphviz, mac下Graphviz安装, pcharm中调用pycharm, Graphviz典型例子

    mac下的Graphviz安装及使用 2017年10月13日 13:30:07 阅读数:7495 一.安装 Graphviz http://www.graphviz.org/ mac用户建议直接用ho ...