C/C++程序内存分配(和Linux进程分配有一些区别)

C/C++程序内存分配

一、一个由C/C++编译到程序占用的内存分为以下几个部分:

1、栈区(stack)——由编译器自动分配释放,在不需要的时候自动清除。用于存放函数的参数、局部变量等。操作方式类似数据结构中的栈(后进先出)。

2、堆区(heap)——一般由程序员分配释放,若程序员分配后不释放,程序结束后可能由OS回收。不同于数据结构中的堆,分配方式有些类似链表。

3、全局区(静态区)——全局变量和静态变量存储在这里。程序结束后由系统释放。在以前到C语言中,全局变量又细分为初始化的(DATA段)和未初始化到(BSS段),在C++里已经没有这个区分了,它们共同占用同一块内存区。

4、常量存储区——常量字符串就存放在这里。一般不允许修改。程序结束后由系统释放。

5、代码区——存放函数体的二进制代码。

示意图如下:

|----------------------|     高地址

|     栈区(Statk)    | -->向下增长

|----------------------|

|     堆区(Heap)    | -->向上增长

|----------------------|

| 未初始化(BSS) |

|----------------------|

|   初始化(Data)   |

|----------------------|

|    常量存储区    |

|----------------------|

|   正文段(Text)   |

|----------------------|    低地址

附上另一副图:

二、一段经典的例子程序,帮助理解

 1 //main.c
 2 #include<string.h>
 3 #include<stdlib.h>
 4 int a = 0;//全局初始化区
 5 char *p1; //全局未初始化区
 6 int main()
 7 {
 8     int b = 0;//栈
 9     char s[] = "abc";//栈
10     char *p2;//栈
11     char *p3 = "123456";//123456\0在常量区,p3在栈上
12     static int c = 0;//全局初始化区
13     p1 = (char *)malloc(10);
14     p2 = (char *)malloc(20);//分配得到到空间在堆区
15     strcpy(p1,"123456");//123456\0放在常量区
16                        //编译器可能会将它与p3所指向的123456\0优化成一个地方
17     return 0;
18 }

Ubuntu下用gcc生成汇编看看,命令:

gcc -S main.c

打开目录下到main.s,汇编代码如下:

 1     .file    "main.c"
 2 .globl a
 3     .bss                   ;大概看出这是BSS段声明
 4     .align 4
 5     .type    a, @object
 6     .size    a, 4
 7  a:
 8     .zero    4
 9     .comm    p1,4,4        ;这里大概就是DATA段
10     .section    .rodata
11 .LC1:
12     .string    "123456"    ;常量存储区
13 .LC0:
14     .string    "abc"       ;栈区
15     .text                  ;代码段
16 .globl main
17     .type    main, @function
18 main:
19     pushl    %ebp
20     movl    %esp, %ebp     ;保存esp现场在ebp中,ebp保存在栈中。Linux下mov a,b是把a赋值给b,与Win下相反
21     andl    $-16, %esp     ;这个貌似是为了对齐神马的
22     subl    $32, %esp      ;分配栈区,用于存放局部变量等。栈区向下增长,因此是减
23     movl    $0, 28(%esp)   ;esp+28,自然是int b = 0;这句
24     movl    .LC0, %eax
25     movl    %eax, 24(%esp) ;char s[] = "abc";
26     movl    $.LC1, 16(%esp);char *p3 = "123456"这句,esp+20是p2,char *p2这句被优化到后面30-32去了
27     movl    $10, (%esp)
28     call    malloc
29     movl    %eax, p1       ;p1 = (char *)malloc(10);
30     movl    $20, (%esp)
31     call    malloc
32     movl    %eax, 20(%esp) ;p2 = (char *)malloc(20);
33     movl    $.LC1, %edx
34     movl    p1, %eax
35     movl    $7, 8(%esp)
36     movl    %edx, 4(%esp)
37     movl    %eax, (%esp)
38     call    memcpy         ;strcpy(p1,"123456")这句,“123456\0”,用的LC1,和上面用的一个
39     movl    $0, %eax       ;return 0;
40     leave
41     ret
42     .size    main, .-main
43     .local    c.1974
44     .comm    c.1974,4,4
45     .ident    "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
46     .section    .note.GNU-stack,"",@progbits

用空再试试-o -o2神马的。还有Win下到反汇编。

Linux下的汇编教程看这里

三、回忆几个题

1、常量存储区的优化

 1 #include<stdio.h>
 2 int main()
 3 {
 4     char str1[] = "hello world";
 5     char str2[] = "hello world";
 6     char* str3 = "hello world";
 7     char* str4 = "hello world";
 8     if(str1 == str2)
 9         printf("str1 and str2 are same.\n");
10     else
11         printf("str1 and str2 are not same.\n");
12
13     if(str3 == str4)
14         printf("str3 and str4 are same.\n");
15     else
16         printf("str3 and str4 are not same.\n");
17     return 0;
18 }
//str1 and str2 are not same.
//str3 and str4 are same.

时间: 2024-08-28 17:04:26

C/C++程序内存分配(和Linux进程分配有一些区别)的相关文章

(笔记)linux 进程和线程的区别

进程:进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程:线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.一个进程由几个线程组成(拥有很多相对独立的执行流的用户程序共享应用程序的大部分数据结构),线程与同属一个进程的其他的线程共享进程所拥有的全部资源. "进程——资源分配的最小单位,线程——程序执行的最小单位" 进程有独立的地址空间,

Linux进程与线程的区别

cnyinlinux 本文较长,耐心阅读,必有收获! 进程与线程的区别,早已经成为了经典问题.自线程概念诞生起,关于这个问题的讨论就没有停止过.无论是初级程序员,还是资深专家,都应该考虑过这个问题,只是层次角度不同罢了.一般程序员而言,搞清楚二者的概念,在工作实际中去运用成为了焦点.而资深工程师则在考虑系统层面如何实现两种技术及其各自的性能和实现代价.以至于到今天,Linux内核还在持续更新完善(关于进程和线程的实现模块也是内核完善的任务之一). 本文将以一个从事Linux平台系统开发的程序员角

Linux进程控制——exec函数族

原文:http://www.cnblogs.com/hnrainll/archive/2011/07/23/2114854.html 1.简介 在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是: #include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char

Linux内存点滴:用户进程内存空间

原文出处:PerfGeeks 经常使用top命令了解进程信息,其中包括内存方面的信息.命令top帮助文档是这么解释各个字段的.VIRT , Virtual Image (kb)RES, Resident size (kb)SHR, Shared Mem size (kb)%MEM, Memory usage(kb)SWAP, Swapped size (kb)CODE, Code size (kb)DATA, Data+Stack size (kb)nFLT, Page Fault countn

C程序内存分配

在多任务操作系统中的每一个进程都运行在一个属于它自己的内存沙盘中.这个沙盘就是虚拟地址空间(virtual address space),在32位模式下它总是一个4GB的内存地址块.这些虚拟地址通过页表(page table)映射到物理内存,页表由操作系统维护并被处理器引用.每一个进程拥有一套属于它自己的页表,但是还有一个隐情.只要虚拟地址被使能,那么它就会作用于这台机器上运行的所有软件,包括内核本身.因此一部分虚拟地址必须保留给内核使用: 这并不意味着内核使用了那么多的物理内存,仅表示它可支配

程序员必读:Linux内存管理剖析

现在的服务器大部分都是运行在Linux上面的,所以作为一个程序员有必要简单地了解一下系统是如何运行的. 对于内存部分需要知道: 地址映射 内存管理的方式 缺页异常 先来看一些基本的知识,在进程看来,内存分为内核态和用户态两部分,经典比例如下: 从用户态到内核态一般通过系统调用.中断来实现.用户态的内存被划分为不同的区域用于不同的目的: 当然内核态也不会无差别地使用,所以,其划分如下: 下面来仔细看这些内存是如何管理的. 地址 在Linux内部的地址的映射过程为逻辑地址–>线性地址–>物理地址,

内存分配原理 -进程分配内存的两种方式,分别有系统调用完成brk() 和mmap()(不设计共享内存)

如何查看进程发生缺页中断的次数? 用ps -o majflt,minflt -C program命令查看. majflt代表major fault,中文名叫大错误,minflt代表minor fault,中文名叫小错误.           这两个数值表示一个进程自启动以来所发生的缺页中断的次数. 发成缺页中断后,执行了那些操作? 当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作: 1.检查要访问的虚拟地址是否合法 2.查找/分配一个物理页 3.填充物理页内容(读取磁盘,或者直接置0

Linux/Unix分配进程ID的方法以及源代码实现

在Linux/Unix系统中.每一个进程都有一个非负整型表示的唯一进程ID.尽管是唯一的.可是进程的ID能够重用.当一个进程终止后,其进程ID就能够再次使用了. 大多数Linux/Unix系统採用延迟重用的算法,使得赋予新建进程ID不同于近期终止进程所使用的ID,这主要是为了防止将新进程误觉得是使用同一ID的某个已终止的先前进程.本文讨论了Linux/Unix分配进程ID的方法以及源代码实现. 分配进程ID的方法 在大多数Linux/Unix系统中,生成一个进程ID方法是:从0開始依次连续分配,

linux进程间的通信(C): 共享内存

一.共享内存介绍 共享内存是三个IPC(Inter-Process Communication)机制中的一个. 它允许两个不相关的进程访问同一个逻辑内存. 共享内存是在两个正在进行的进程之间传递数据的一种非常有效的方式. 大多数的共享内存的实现, 都把由不同进程之间共享的内存安排为同一段物理内存. 共享内存是由IPC为进程创建一个特殊的地址范围, 它将出现在该进程的地址空间中. 其他进程可以将同一段共享内存连接它们自己的地址空间中. 所有进程都可以访问共享内存中的地址, 就好像它们是由mallo