zoukankan      html  css  js  c++  java
  • C语言程序内存的分区

    本文转载自:https://blog.csdn.net/shulianghan/article/details/20472269

    C语言程序内存分配

    (1) 内存分区状况

    栈区 (stack) : 

    -- 分配, 释放方式 : 由编译器自动分配 和 释放;

    -- 存放内容 : 局部变量, 参数;

    -- 特点 : 具有 后进先出 特性, 适合用于 保存 回复 现场;

    堆区 (heap) : 

    -- 分配, 释放方式 : 由程序员手动 分配(malloc) 和 释放(free), 如果程序员没有释放, 那么程序退出的时候, 会自动释放;

    -- 存放内容 : 存放程序运行中 动态分配 内存的数据;

    -- 特点 : 大小不固定, 可能会动态的 放大 或 缩小;

    堆区内存申请 : 

    -- 申请过程 : OS中有一个记录空闲内存地址的链表, 如果程序员申请内存, 就会找到空间大于申请内存大小的节点, 将该节点从空间内存链表中删除, 并分配该节点; 

    -- 剩余内存处理 : 系统会将多余的部分重新放回 空闲内存链表中;

    -- 首地址记录大小 : 分配内存的首地址存放该堆的大小, 这样释放内存的时候才能正确执行; 

    全局区/静态区 (数据段 data segment / bss segment) : 

    -- 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;

    -- 存放内容 : 全局变量, 静态变量;

    -- 特点 : 全局变量 和 静态变量存储在一个区域, 初始化的两种变量 和 未初始化的 存储在不同区域, 但是两个区域是相邻的;

    常量区 : 

    -- 分配, 释放方式 : 退出程序由系统自动释放;

    -- 存放内容 : 常量; (比如char *s = "hello",此处的hello就存储在常量区)


    代码区 (text segment) : 

    -- 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;

    -- 存放内容 : 存放函数体的二进制代码。

    内存存放顺序 (由上到下) : 栈区 -> 堆区 -> 全局区 -> 常量区 -> 代码区;

    (2) 内存分配方式

    全局内存分配 : 

    -- 生命周期 : 编译时分配内存, 程序退出后释放内存, 与 程序 的生命周期相同;

    -- 存储内容 : 全局变量, 静态变量;

    栈内存分配 :

    -- 生命周期 : 函数执行时分配内存, 执行结束后释放内存;

    -- 特点 : 该分配运算由处理器处理, 效率高, 但是栈内存空间有限;

    堆内存分配 : 

    -- 生命周期 : 调用 malloc()开始分配, 调用 free()释放内存, 完全由程序员控制;

    -- 谨慎使用 : 如果分配了 没有释放, 会造成内存泄露, 如果频繁 分配 释放 会出现内存碎片; 

    (3) register变量

    使用场景 : 如果 一个变量使用频率特别高, 可以将这个变量放在 CPU 的寄存器中;

    -- 修饰限制 : 只有 局部变量 和 参数 可以被声明为 register变量, 全局 和 静态的不可以;

    -- 数量限制 : CPU 寄存器 很宝贵, 不能定义太多register变量;

    (4) extern 变量

    extern变量概念 : 声明外部变量, 外部变量就是在函数的外部定义的变量, 在本函数中使用;

    -- 作用域 : 从外部变量定义的位置开始, 知道本源码结束都可以使用, 但是只能在定义extern后面使用, 前面的代码不能使用;

    -- 存放位置 : 外部变量 存放在 全局区;

    extern变量作用 : 使用extern修饰外部变量, ① 扩展外部变量在本文件中的作用域, ② 将外部变量作用域从一个文件中扩展到工程中的其它文件;

    extern声明外部变量的情况 : 

    -- 单个文件内声明 : 如果不定义在文件开头, 其作用范围只能是 定义位置开始, 文件结束位置结束;

    -- 多个文件中声明 : 两个文件中用到一个外部变量, 只能定义一次, 编译 和 连接的时候, 如果没有这个外部变量, 系统会知道这个外部变量在别处定义, 将另一个文件中的外部变量扩展到本文件中;

    extern编译原则 : 

    -- 本文件中能找到 : 编译器遇到 extern 的时候, 现在本文件中找外部变量的定义的位置, 如果找到, 就将作用域扩展到 定义的位置 知道文件结束;

    -- 本文件中找不到 : 如果本文件中找不到, 连接其它文件找外部变量定义, 如果找到, 将外部变量作用域扩展到本文件中;

    -- 外部文件找不到 : 报错;

    使用效果 : extern 使用的时候, 可以不带数据类型;

    -- 本文件 : int A = 0; 在第10行, extern A 在第一行, 那么A的作用域就扩展为从第一行到文件末尾;

    -- 多文件 : 在任意文件中定义了 int A = 0; 在本文件中声明 extern A, 那么从当前位置到文件末尾都可以使用该变量;

    (5) static变量 与 全局变量区别

    static 变量 与 全局变量 相同点 : 全局变量是静态存储的, 存储的方式 和 位置基本相同;

    static 变量 与 全局变量的不同点 : 全局变量的作用域是 整个项目工程 横跨过个文件, 静态变量的作用域是 当前文件, 其它文件中使用是无效的;

    变量存储位置 : 全局变量 和 静态变量 存放在 全局区/静态区, 局部变量存放在 栈区(普通变量) 和 堆区(指针变量);

    变量静态化 : 

    -- 局部变量 : 局部变量 加上 static , 相当于将局部变量的生命周期扩大到了整个文件, 作用域不改变;

    -- 全局变量 : 全局变量 加上 static , 相当于将全局变量的作用域缩小到了单个文件, 生命周期是整个程序的周期;

    关于函数头文件的引申 : 

    -- 内部函数 : 单个文件中使用的内部函数, 仅在那个特定文件中定义函数即可;

    -- 全局函数 : 如果要在整个工程中使用一个全局函数, 需要将这个函数定义在一个头文件中;

    static变量与普通变量区别 : 

    -- static全局变量 与 全局变量区别 : static 全局变量 只初始化一次, 防止在其它文件中使用;

    -- static局部变量 与 局部变量区别 : static 局部变量 只初始化一次, 下一次依据上一次结果;

    static函数与普通函数区别 : static 函数在内存中只保留一份, 普通函数 每调用一次, 就创建一个副本;

    (6) 堆 和 栈比较

    堆(heap)和栈(stack)区别 : 

    -- 申请方式 : stack 由系统自动分配, heap 由程序员进行分配;

    -- 申请响应 : 如果 stack 没有足够的剩余空间, 就会溢出; 堆内存从链表中找空闲内存;

    -- 内存限制 : stack 内存是连续的, 从高位向低位扩展, 而且很小, 只有几M, 是事先定好的, 在文件中配置; heap 是不连续的, 从低位向高位扩展, 系统是由链表控制空闲程序, 链表从低地址到高地址, 堆大小受虚拟内存限制, 一般32位机器有4G heap;

    -- 申请效率 : stack 由系统分配, 效率高; heap 由程序员分配, 速度慢, 容易产生碎片;

    (7) 各区分布情况

    由上到下顺序 : 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区;

    验证分区状况 : 

    -- 示例程序 : 

     1 /*************************************************************************
     2     > File Name: memory.c
     3     > Author: octopus
     4     > Mail: octopus_work.163.com 
     5     > Created Time: Mon 10 Mar 2014 08:34:12 PM CST
     6  ************************************************************************/
     7  
     8 #include<stdio.h>
     9 #include<stdlib.h>
    10  
    11 int global1 = 0, global2 = 0, global3 = 0;
    12  
    13 void function(void)
    14 {
    15         int local4 = 0, local5 = 0, local6 = 0;
    16         static int static4 = 0, static5 = 0, static6 = 0;
    17         int *p2 = (int*)malloc(sizeof(int));
    18  
    19         printf("子函数 局部变量 : 
    ");
    20         printf("local4 : %p 
    ", &local4);
    21         printf("local5 : %p 
    ", &local5);
    22         printf("local6 : %p 
    ", &local6);
    23  
    24         printf("子函数 指针变量 : 
    ");
    25         printf("p2 : %p 
    ", p2);
    26  
    27         printf("全局变量 : 
    ");
    28         printf("global1 : %p 
    ", &global1);
    29         printf("global2 : %p 
    ", &global2);
    30         printf("global3 : %p 
    ", &global3);
    31  
    32         printf("子函数 静态变量 : 
    ");
    33         printf("static4 : %p 
    ", &static4);
    34         printf("static5 : %p 
    ", &static5);
    35         printf("static6 : %p 
    ", &static6);
    36  
    37         printf("子函数地址 : 
    ");
    38         printf("function : %p 
    ", function);
    39 }
    40  
    41 int main(int argc, char **argv)
    42 {
    43         int local1 = 0, local2 = 0, local3 = 0;
    44         static int static1 = 0, static2 = 0, static3 = 0;
    45         int *p1 = (int*)malloc(sizeof(int));
    46         const int const1 = 0;
    47         char *char_p = "char";
    48  
    49         printf("主函数 局部变量 : 
    ");
    50         printf("local1 : %p 
    ", &local1);
    51         printf("local2 : %p 
    ", &local2);
    52         printf("local3 : %p 
    ", &local3);
    53         printf("const1 : %p 
    ", &const1);
    54  
    55         printf("主函数 指针变量 : 
    ");
    56         printf("p1 : %p 
    ", p1);
    57  
    58         printf("全局变量 : 
    ");
    59         printf("global1 : %p 
    ", &global1);
    60         printf("global2 : %p 
    ", &global2);
    61         printf("global3 : %p 
    ", &global3);
    62  
    63         printf("主函数 静态变量 : 
    ");
    64         printf("static1 : %p 
    ", &static1);
    65         printf("static2 : %p 
    ", &static2);
    66         printf("static3 : %p 
    ", &static3);
    67  
    68         printf("字符串常量 : 
    ");
    69         printf("char_p : %p 
    ", char_p);
    70  
    71         printf("主函数地址 : 
    ");
    72         printf("main : %p 
    ", main);
    73  
    74  
    75         printf("= = = = = = = = = = = = = = = 
    ");
    76  
    77         function();
    78  
    79         return 0;
    80 }

    -- 执行结果 : 

     1 [root@ip28 pointer]# gcc memory.c 
     2 [root@ip28 pointer]# ./a.out 
     3 主函数 局部变量 : 
     4 local1 : 0x7fff75f5eedc 
     5 local2 : 0x7fff75f5eed8 
     6 local3 : 0x7fff75f5eed4 
     7 const1 : 0x7fff75f5eed0 
     8 主函数 指针变量 : 
     9 p1 : 0x19bad010 
    10 全局变量 : 
    11 global1 : 0x600e14 
    12 global2 : 0x600e18 
    13 global3 : 0x600e1c 
    14 主函数 静态变量 : 
    15 static1 : 0x600e34 
    16 static2 : 0x600e30 
    17 static3 : 0x600e2c 
    18 字符串常量 : 
    19 char_p : 0x4009f7 
    20 主函数地址 : 
    21 main : 0x40065f 
    22 = = = = = = = = = = = = = = = 
    23 子函数 局部变量 : 
    24 local4 : 0x7fff75f5eea4 
    25 local5 : 0x7fff75f5eea0 
    26 local6 : 0x7fff75f5ee9c 
    27 子函数 指针变量 : 
    28 p2 : 0x19bad030 
    29 全局变量 : 
    30 global1 : 0x600e14 
    31 global2 : 0x600e18 
    32 global3 : 0x600e1c 
    33 子函数 静态变量 : 
    34 static4 : 0x600e28 
    35 static5 : 0x600e24 
    36 static6 : 0x600e20 
    37 子函数地址 : 
    38 function : 0x400528 
  • 相关阅读:
    找不到vc_runtimeMinimum_x86.msi!
    ubuntu开启coredump
    log4j2项目打成jar包运行日志无法打印
    linux 下使用 tc 模拟网络延迟和丢包
    Spring MVC
    typora实现图片上传
    java异常和调优
    java线程
    java三大特征
    webstorm如何更换主题以及更换主题后字体缩放问题
  • 原文地址:https://www.cnblogs.com/FengZeng666/p/9643494.html
Copyright © 2011-2022 走看看