观察Linux内存分配结果

发布于 2019-05-16  398 热度


1       实训目的

通过分析C程序中全局变量、局部变量、静态变量以及malloc函数成功分配的区域的地址,观察总结Linux对进程栈段、数据段、堆段、代码段的内存分配与管理机制,理解Linux的虚拟内存技术。

2       实训内容

  • 了解Linux进程空间布局。
  • 了解malloc函数的功能和Linux虚拟内存管理的原理。
  • 编写一个(语言程序,定义两个初始化的全局变量和两个未初站化的金局变量,再在main雨数中分别定义一个初始化和一个未初始化的静态变量,以及三个局部变量,然后用malloc函数申请三段1 KB的存储空间和三段与内存容量等大小的存储空间,最后在终端上显示所有变量和malloc函数成功分配的区域的起始地址。
  • 运行该程序,观察、记录其运行结果,并分析说明结果的地址是否为物理地址。

3       内存分配代码

编写代码memory.c。

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

//定义两个初始化的全局变量 
int data_var0 = 10;
int data_var1 = 10;
//定义两个未初始化的全局变量
int bss_var0;
int bss_var1; 
int main()
{
    //分别定义一个初始化和一个未初始化的静态变量
	static int data_var2 = 10;
	static int bss_var2;
	
	//定义三个局部变量
	int stack_var0 = 1;
	int stack_var1 = 1;
	int stack_var2 = 1; 
	
	printf("--------TEXT Segment--------\n");
	printf("Address of main: %p\n",main);
	printf("--------DATA Segment--------\n");
	printf("Address of data_var0: %p\n",&data_var0);
	printf("Address of data_var1: %p\n",&data_var1);
	printf("Address of data_var2: %p\n",&data_var2);
	printf("--------BSS Segment--------\n");
	printf("Address of bss_var0: %p\n",&bss_var0);
	printf("Address of bss_var1: %p\n",&bss_var1);
	printf("Address of bss_var2: %p\n",&bss_var2);
	printf("--------STACK Segment--------\n");
	printf("Address of stack_var0: %p\n",&stack_var0);
	printf("Address of stack_var1: %p\n",&stack_var1);
	printf("Address of stack_var2: %p\n",&stack_var2);
	
	//使用malloc分配三个大小为1024B的内存
	char *heap_var0 = (char *)malloc(1024); 
	char *heap_var1 = (char *)malloc(1024); 
	char *heap_var2 = (char *)malloc(1024); 
	printf("--------HEAP Segment--------\n");
	if(heap_var0){//分配成功 
		printf("Address of heap_var0: %p\n",heap_var0);	
		free(heap_var0);//释放空间
		heap_var0 = NULL; 
	}
	if(heap_var1){//分配成功 
		printf("Address of heap_var1: %p\n",heap_var1);	
		free(heap_var1);//释放空间
		heap_var1 = NULL; 
	}
	if(heap_var2){//分配成功 
		printf("Address of heap_var2: %p\n",heap_var2);	
		free(heap_var2);//释放空间
		heap_var2 = NULL; 
	}
	
	//使用malloc分配三个大小为512MB的内存
	char *mmap_var0 = (char *)malloc(1024 * 1024 *512); 
	char *mmap_var1 = (char *)malloc(1024 * 1024 *512); 
	char *mmap_var2 = (char *)malloc(1024 * 1024 *512); 
	printf("--------MMAP--------\n");
	if(mmap_var0){//分配成功 
		printf("Address of mmap_var0: %p\n",mmap_var0);	
		free(mmap_var0);//释放空间
		mmap_var0 = NULL; 
	}
	if(mmap_var1){//分配成功 
		printf("Address of mmap_var1: %p\n",mmap_var1);	
		free(mmap_var1);//释放空间
		mmap_var1 = NULL; 
	}
	if(mmap_var2){//分配成功 
		printf("Address of mmap_var2: %p\n",mmap_var2);	
		free(mmap_var2);//释放空间
		mmap_var2 = NULL; 
	}

    return 0;
}

4       运行结果及分析

使gcc memory.c –o memory编译链接后,运行两次,其运行结果如图所示。

观察Linux内存分配结果 观察Linux内存分配结果

从两次运行结果可以看出:

  1. 两个初始化的全局变量和一个初始化的静态局部变量,在数据段中分配;数据段地址空间在代码段之上。
  2. 两个未初始化的全局变量和.个未初始化的静态局部变量,在BSS段中分配;BSS段地址空间在数据段之上。
  3. 三个局部变量在栈中定义,栈空间的地址从0xfff开始,从高地址向低地址增长。
  4. 使用malloc分配的三个1024B的内存区域,在堆中分配;堆地址空间在BSS段之上从低地址向高地址增长。
  5. 使用malloc分配的三个512MB大小的内存区域,在堆及栈之间的空间分配。
  6. malloc针对大小不同的内存请求在不同的地方分配内存,是由malloc策略决定的,不同的glibc(GNU C Library的简称,是GNU按照LGPL许可协议发布的C运行库,通常作为GNUC编译程序的一个部分,是linux系统最底层的API接口)版本(可用rpm命令查看)可能有所不同。一般情况下,对于小于等于128 KB的内存请求,malloe在堆中分配内存;对于大于128KB的内存请求,malloc使用mmap系统调用函数在堆和栈之间的空间(Windows中称为文件映射区域)分配可用内存。
  7. 本示例运行环境中只有512MB物理内存,却能分配三个512MB的内存,进一步说明了malloc分配的是进程虚拟内存,而不是物理内存。
  8. 代码段、数据段、BSS段中变量的地址一致,它们在编译时确定,不再改变;而栈、堆以及文件映射区域中的地址不一致,这是由程序在运行时动态分配的。

注意:读者若尝试用malloc分配更大的内存空间,需防止可能分配失败,故代码中应判断malloc的返回结果。同时,内存使用完毕后,应调用free函数释放内存,并将其置为NULL,以避免内存泄露和使用野指针。


我一直在开辟我的天空