Linux内存管理(一)

最近引擎版本上线,测试人员发现一个"奇怪问题",引擎实例不停的创建和销毁过程中,内存增长过快,看起来很像是内存泄漏,但是工具valgrind跑出来,也没发现代码的泄漏点,跑了很多次循环后,内存增加到一定后,就表现平稳,所以近期抽点时间,系统的学习下linux系统内存管理方式

本次从以下四个问题出发:

1.Linux虚拟地址如何分布? 我们常常说的 32位和64为有啥不同? 虚拟地址和物理地址区别?

2. 如何分配内存, malloc ?

3.malloc 是在虚拟地址 ? 物理地址分配内存,程序需要多少内存,就真的分配多大物理内存么?

4.进程虚拟地址空间使用情况?

 

问题一:

(1).只读段:该部分空间 只能读,不可写,包括代码段,(C常量字符串 和 宏定义定义的常量)

(2).数据段: 保存全局变量,静态变量空间

(3).堆空间: new/delete ,malloc/free 内存大部分在此创建,堆顶位置可通过函数brk,和sbrk进行动态申请,

sbrk( >0 的size)映射一个4k的page,并且分配一个空间,得到没有映射的虚拟地址,使用brk分配空间,

brk一般配合这sbrk做申请内存和释放内存使用,使用sbrk得到地址后,使用brk做偏移

(4).文件映射区域:如动态库,共享内存等映射物理空间内存,一般是mmap函数分配的虚拟地址空间,内存映射函数mmap,负责把文件内容映射到进程虚拟内存空间,通过对这段内存读取和修改,来实现对文件的读取和修改

(5).栈: 用于维护函数调用的上下文空间,一般是8M ,ulimit -s查看

(6).内核虚拟空间,用户代码不可见内存区域

 

32位的操作系统有4G地址空间,其中 0x8048000 ~ 0xbfffffff 是用户空间,0xc000000 ~ 0xfffffff

是内核空间,包括内核代码和数据,进程相关的数据结构 页表,内核栈,指针%esp指针在栈顶,往低地址方向移动。堆内存控制函数

brk、sbrk控制堆顶向高地址方向变化

64位操作系统地址空间不是2的32次方,也不是2的64次方。一般是2的48次方(256TB寻址空间),实际不需要2的64次方这么大的寻址空间。

问题二(malloc 是如何分配内存):

malloc是glibc中内存分配函数,也是最常用的动态内存分配函数,malloc是配合free进行释放,否则导致内存泄漏,以下为最常用的流程:

a. 分配内存< 128k,调用sbrk(),将堆顶指针指向高地址,获取虚拟空间

b.分配内存> 128k,调用mmap(),在文件映射区域中分配匿名虚拟空间

128k 是 glibc 的默认配置,可通过函数 mallopt 

问题三(malloc 分配虚拟内存和物理内存区别):

1.malloc 分配的内存是虚拟地址空间的内存,实际使用的物理地址的内存是 虚拟地址空间使用进程页表进行映射,如下实例:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <malloc.h>

char ps_cmd[1024];
void print_info(char* var_name,char* var_ptr,size_t size_in_kb)
{
        printf("Address of %s(%luk) 0x%lx,  now heap top is 0x%lx\n",
                 var_name, size_in_kb, var_ptr, sbrk(0));
        system(ps_cmd);
}

int main(int argc, char** argv)
{
        char *non_set_var, *set_1k_var, *set_5k_var, *set_7k_var;
        pid_t pid;
        pid = getpid();
        sprintf(ps_cmd, "ps aux | grep %lu | grep -v grep", pid);

        non_set_var = (char*)malloc(32*1024);
        print_info("non_set_var", non_set_var, 32);

        set_1k_var = malloc(64*1024);
        memset(set_1k_var, 0, 1024);
        print_info("set_1k_var", set_1k_var, 64);

        set_5k_var =(char*)malloc(127*1024);
        memset(set_5k_var, 0, 5*1024);
        print_info("set_5k_var", set_5k_var, 127);


        set_7k_var = (char*)malloc(64*1024);
        memset(set_1k_var, 0, 7*1024);
        print_info("set_7k_var", set_7k_var, 64);

        return 0;
}

总结(ps aux 获取当前进程的VSZ(虚拟内存),RSS(物理内存)大小):

1. VSZ并不是每次malloc都是增长,主要是看堆顶指针变化没有,因为malloc后 堆顶内存可以重用,不需要重新移动指针来开辟内存

2.VSZ发生变化时,变化的大小基本与程序分配的大小基本差不多

3.malloc分配的内存 并不是立即分配实际的物理内存,只有使用实际内存时候 才会分配物理内存

4.每个物理内存页面大小是4k,实际占用物理内存一定是4k的倍数

所以: 并不是malloc后马上就占用实际的物理内存,RSS不是立即增加,而是使用时发现虚拟内存中对应的物理页面未分配,产生缺页中断,才会分配实际的物理内存。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值