`
laoyao319
  • 浏览: 13450 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类

C程序内存布局

 
阅读更多

1、堆和栈的区别,堆和栈的最大限制

    堆主要用来分配动态内存,操作系统提供了malloc等内存分配机制来供程序员进行堆内存的分配,同时,堆内存的释放需要程序员来进行。malloc分配的是虚拟地址空间,和用到的实实在在的物理内存是两码事,只有真正往空间里写东西了,os内核会触发缺页异常,然后才真正得到物理内存。32位Linux系统总共有4G内存空间,Linux把最高的1G(0xC0000000-0xFFFFFFFF)作为内核空间,把低地址的3G(0x00000000-0xBFFFFFFF)作为用户空间。malloc函数在这3G的用户空间中分配内存,能分配到的大小不超过3G,需除去栈、数据段(初始化及未初始化的)、共享so及代码段等占的内存空间。
堆的地址空间是由低向高增长的(先分配低地址)。我用以下程序进行测试:

点击(此处)折叠或打开

  1. #include <stdio.h> 
  2. #include <stdlib.h> 

  3. int main(int argc, char *argv[]) 
  4. { 
  5.      char *ch = NULL; 
  6.      unsigned int size = 2147 * 1000000; 
  7.      ch = (char *)malloc(size); 
  8.      if(ch == NULL) 
  9.          perror("malloc failed\n"); 
  10.      else 
  11.          printf("malloc success\n"); 
  12.      free(ch); 
  13.      return 0; 
  14. }
发现最大能分配的内存约为2.147GB。 
为什么这么说: 我们可以看malloc函数的原型void *malloc(size_t size); size_t 在stddef.h里定义的是unsigned int类型,故在ilp32平台上其最大取值是2147483647

   栈由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。栈的地址空间是由高向低减少的(先分配高地址)。在Linux中,用ulimit -a命令可以看到栈的最大分配空间(stack size)是8192kB,即8MB多。

 2、Linux中进程最大地址空间

Linux的虚拟地址空间也为0~4G。Linux内核将虚拟的4G字节的空间分为两部分。
将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为"内核空间"。将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为"用户空间"。因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。
其中,很重要的一点是虚拟地址空间,并不是实际的地址空间。进程地址空间是用多少分配多少,4G仅仅是最大限额而已。往往,一个进程的地址空间总是小于4G的,你可以通过查看/proc/pid/maps文件来获悉某个具体进程的地址空间。但进程的地址空间并不对应实际的物理页,Linux采用Lazy的机制来分配实际的物理页("Demand paging"和"和写时复制(Copy On Write)的技术"),从而提高实际内存的使用率。即每个虚拟内存页并不一定对应于物理页。虚拟页和物理页的对应是通过映射的机制来实现的,即通过页表进行映射到实际的物理页。因为每个进程都有自己的页表,因此可以保证不同进程从上到下(地址从高到低)依次为栈(函数内部局部变量),堆(动态分配内存) ,bss段(存未初始化的全局变量),数据段(存初始化的全局变量),文本段(存代码)同虚拟地址可以映射到不同的物理页,从而为不同的进程都可以同时拥有4G的虚拟地址空间提供了可能。

3、C/C++程序在Linux中的内存布局

用以下程序进行测试

点击(此处)折叠或打开

  1. #include <stdio.h> 
  2. #include <stdlib.h> 

  3. char bss_1[40]; 
  4. static double bss_2; 
  5. int data_1 = 13; 
  6. static long data_2 = 2001; 

  7. int main(int argc, char *argv[]) 
  8. { 
  9.     int stack_1 = 3, stack_2, *heap_1, *heap_2; 
  10.     heap_1 = malloc(sizeof(stack_1)); 
  11.     heap_2 = malloc(sizeof(stack_1)); 
  12.     bss_1[5] = stack_1; 
  13.     bss_2 = 2.* data_1; 
  14.     printf("stack segment: stack_1:%p, stack_2:%p\n", &stack_1, &stack_2); 
  15.     printf("heap segment: heap:heap_1:%p, heap_2:%p\n", heap_1, heap_2); 
  16.     printf("bss segment: bss_1:%p, bss_2:%p\n", bss_1, &bss_2); 
  17.     printf("data segment: data_1:%p, data_2:%p\n", &data_1, &data_2); 
  18.     printf("the stack top is near %p\n", &stack_1); 
  19.     return 0; 
  20. }
运行结果:
stack segment: stack_1:0xbfab012c, stack_2:0xbfab0128
stack segment: stack_1:0xbfb9e2ec, stack_2:0xbfb9e2e8
heap segment: heap:heap_1:0x8c56008, heap_2:0x8c56018
bss segment:  bss_1:0x804a040, bss_2:0x804a028
data segment: data_1:0x804a018, data_2:0x804a01c
the stack top is near 0xbfb9e2ec

由此可见:从上到下(地址从高到低)依次为栈(函数内部局部变量),动态链接库,堆(动态分配内存),bss段(存未初始化的全局变量),数据段(存初始化的全局变量),文本段(存代码)

分享到:
评论

相关推荐

    内存布局1

    在分析程序内存布局时,例如使用WinHex这样的十六进制编辑器,我们可以: - **搜索字符串**:寻找程序中的关键信息,如登录账户、密码提示等。 - **修改跳转**:如果不能直接找到敏感信息,可以考虑修改程序的...

    C例子:程序内存模型

    该程序是我写的博客“一起talk C栗子吧(第一百三十回:C语言实例--C程序内存布局二)”的配套程序,共享给大家使用

    程序布局原理 布局 风格分析

    通过合理的内存布局和编码风格,开发者不仅可以优化程序性能,还能提升代码的可维护性,进而确保软件项目的稳定发展。无论是个人开发者还是团队,都需要通过不断学习和实践这些原则,才能编写出更加高效、可靠且易于...

    C++对象内存布局[归类].pdf

    C++对象内存布局 C++对象内存布局是指在C++编程语言中对象在内存中的存储结构和布局方式。...通过了解C++对象的内存布局,可以更好地理解C++编程语言的工作机制,从而编写出更加高效、稳定的程序。

    应用 Valgrind 发现 Linux 程序的内存问题1

    **Linux程序内存空间布局** 在Linux系统中,一个典型的C程序内存布局包含以下部分: 1. **代码段(.text)**:存储可执行的指令,只读且可共享。 2. **初始化数据段(.data)**:存储初始化的全局变量和静态变量。 3. **...

    C语言程序内存布局

    C语言通过栈来维护函数调用上下文,也就是说C中的函数、函数参数列表、局部变量、函数返回值都保存在栈内存中,在完成函数调用之后栈帧随即销毁,至于具体的压栈顺序和上下文维护工作由谁来完成,则取决于函数的调用...

    类的对象的内存布局

    而成员函数,不管是静态的还是非静态的,都不会占用对象的内存空间,它们一般位于程序的代码段中,而非对象的内存布局之中。 当类涉及到继承时,尤其是基类中含有虚函数时,事情就变得复杂起来。虚函数是实现多态的...

    U-BOOT 内存布局及启动过程浅析

    ### U-BOOT内存布局及启动过程浅析 #### 一、U-BOOT内存布局解析 U-BOOT(Universal Boot Loader)是一种广泛应用于嵌入式系统的引导加载程序,它支持多种处理器架构和各种嵌入式设备。U-BOOT的内存布局对于理解和...

    C++对象内存布局

    ### C++对象内存布局 #### 1. 最简单的类 在C++中,理解对象的内存布局对于深入学习语言特性非常关键。通过分析一个简单的类`CTest`,我们可以更好地了解对象是如何在内存中分配和组织的。 ##### 1.1.1 赋值语句...

    Java对象内存布局 - 小分析

    理解对象内存布局有助于优化程序性能,例如减少对象创建、理解和使用对象池,或者通过调整JVM参数来改善垃圾回收效率。`SizeOfAgent.java`、`Rule1.java`和`Rule2.java`可能包含了用于分析对象大小的代码,而`rule1....

    易语言分析数据类型内存布局

    理解数据类型的内存布局对于深入学习易语言编程以及优化程序性能至关重要。 在易语言中,数据类型主要包括基本类型、复合类型和自定义类型。基本类型如整型、实型、字符型等,它们在内存中的布局通常是连续的字节...

    C语言内存精讲,让你彻底明白C语言的运行机制!

    8. Linux下C语言程序的内存布局(内存模型) 9. Windows下C语言程序的内存布局(内存模型) 10. 用户模式和内核模式 11. 栈(Stack)是什么?栈溢出又是怎么回事? 12. 一个函数在栈上到底是怎样的? 13. 函数调用...

    BIOS内存布局图

    了解BIOS内存布局对于深入理解计算机系统运行机制至关重要。在C语言的学习过程中,掌握内存布局有助于编写更高效、更安全的代码。 BIOS内存布局通常包括以下几个关键区域: 1. **引导扇区**:位于硬盘的0磁道0柱面...

    C语言程序的内存布局[参考].pdf

    C语言程序的内存布局是理解程序执行过程的关键。在C语言中,程序的内存主要划分为以下几个区域: 1. **代码段(Code or Text)**:这是程序的机器码所在的地方,由编译器将源代码编译成的指令构成。在程序运行时,...

    程序内存分析工具

    通过Vmmap,用户可以详细地查看和分析任何进程的虚拟内存布局,包括堆、栈、映射文件、空闲区域等。它能提供关于内存分配、使用和效率的详尽信息,对于调试内存泄漏、性能瓶颈和理解进程内存工作原理非常有帮助。 ...

    易语言分析数据类型内存布局源码

    这些数据类型的内存布局直接影响到程序的运行效率和内存使用。 2. **数据类型内存布局** - **基本类型**:整数型在内存中通常按照机器字长对齐存储,例如,在32位系统中,一个整数占用4个字节,而在64位系统中,长...

    um-b-011_da14580_memorymap_and_scatter_filev1.1.pdf

    而散列文件则是链接器用来控制程序内存布局的文件,它描述了程序如何被加载到内存中的不同区域。 文档内容可以分为以下几个主要部分: 1. 内存映射(Memory Map):在第5节中,文档会详细说明DA14580-01的内存分配...

    汇编语言程序执行的过程.docx

    2. **程序内存布局**: - DS寄存器中存放了程序所在内存区域的段地址。 - 内存区域的前256字节用于存放PSP(程序段前缀),这是DOS与程序之间通信的桥梁。 - 从256字节之后开始存放程序本身。 - 因此,程序的...

    STM32内存知识.doc

    在开发过程中,使用MDK(Keil Microcontroller Development Kit)编译器时,生成.map文件可以帮助分析程序内存布局。勾选生成.map选项,编译后即可得到.map文件。这个文件包含了程序的内存映射信息,包括代码段、...

Global site tag (gtag.js) - Google Analytics