加入收藏 | 设为首页 | 会员中心 | 我要投稿 佛山站长网 (https://www.0757zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux 用户进程内存空间详解

发布时间:2016-10-28 06:49:38 所属栏目:Linux 来源:网络整理
导读:常使用top命令了解进程信息,其中包括内存方面的信息。命令top帮助文档是这么解释各个字段的。 VIRT, Virtual Image (kb) RES, Resident size (kb) SHR, Shared

编码人员在编写程序之际,时常要处理变化数据,无法预料要处理的数据集变化是否大(phper可能难以理解),所以除了变量之外,还需要动态分配内存。GNU libc库提供了二个内存分配函数,分别是malloc()和calloc()。调用malloc(size_t size)函数分配内存成功,总会分配size字节VM(再次强调不是RAM),并返回一个指向刚才所分配内存区域的开端地址。分配的内存会为进程一直保留着,直到你显示地调用free()释放它(当然,整个进程结束,静态和动态分配的内存都会被系统回收)。开发人员有责任尽早将动态分配的内存释放回系统。记住一句话:尽早free()!

我们来看看,malloc()小示例。

/* @filename:example_2_4.c */
#include <stdio.h>  
#include <stdlib.h>  
       
int main(int argc, char *argv[])  
{  
    char *p_4kb, *p_128kb, *p_300kb;  
    if ((p_4kb = malloc(4*1024)) != NULL)  
    {  
        free(p_4kb);  
    }  
    if ((p_128kb = malloc(128*1024)) != NULL)  
    {  
        free(p_128kb);  
    }  
    if ((p_300kb = malloc(300*1024)) != NULL)  
    {  
        free(p_300kb);  
    }  
    return 0;  
}
#gcc example_2_4.c –o example_2_4  
#strace –t ./example_2_4  
…  
00:02:53 brk(0)                         = 0x8f58000  
00:02:53 brk(0x8f7a000)                 = 0x8f7a000  
00:02:53 brk(0x8f79000)                 = 0x8f79000  
00:02:53 mmap2(NULL, 311296, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb772d000  
00:02:53 munmap(0xb772d000, 311296)     = 0  
…

PS:系统调用brk(0)取得当前堆的地址,也称为断点。

通过跟踪系统内核调用,可见glibc函数malloc()总是通过brk()或mmap()系统调用来满足内存分配需求。函数malloc(),根据不同大小内存要求来选择brk(),还是mmap(), 128Kbytes是临界值。小块内存(<=128kbytes),会调用brk(),它将数据段的最高地址往更高处推(堆从底部向上增长)。大块内存,则使用mmap()进行匿名映射(设置标志MAP_ANONYMOUS)来分配内存,与堆无关,在堆之外。这样做是有道理的,试想:如果大块内存,也调用brk(),则容易被小块内存钉住,必竟用大块内存不是很频繁;反过来,小块内存分配更为频繁得多,如果也使用mmap(),频繁的创建内存映射会导致更多的开销,还有一点就是,内存映射的大小要求必须是“页”(单位,内存页面大小,默认4Kbytes或8Kbytes)的倍数,如果只是为了”hello world”这样小数据就映射一“页”内存,那实在是太浪费了。

跟malloc()一样,释放内存函数free(),也会根据内存大小,选择使用brk()将断点往低处回推,或者选择调用munmap()解除映射。有一点需要注意:并不是每次调用free()小块内存,都会马上调用brk(),即堆并不会在每次内存被释放后就被缩减,而是会被glibc保留给下次malloc()使用(必竟小块内存分配较为频繁),直到glibc发现堆空闲大小显著大于内存分配所需数量时,则会调用brk()。但每次free()大块内存,都会调用munmap()解除映射。下面是二张malloc()小块内存和大块内存的示例图。

示意图:函数malloc(100000),小于128kbytes,往高处推(heap->)。留意紫圈标注

示意图:函数malloc(1024*1024),大于128kbytes,在heap与stack之间。留意紫圈。PS:图中的Data Segment泛指BSS, Data, Heap。有些文档有说明:数据段有三个子区域,分别是BSS, Data, Heap。

缺页异常(Fault Page)

每次调用malloc(),系统都只是给进程分配线性地址(VM),并没有随即分配页框(RAM)。系统尽量将分配页框的工作推迟到最后一刻—用到时缺页异常处理。这种页框按需延迟分配策略最大好处之一:充分有效地善用系统稀缺资源RAM。

当指针引用的内存页没有驻留在RAM中,即在RAM找不到与之对应的页框,则会发生缺页异常(对进程来说是透明的),内核便陷入缺页异常处理。发生缺页异常有几种情况:1.只分配了线性地址,并没有分配页框,常发生在第一次访问某内存页。2.已经分配了页框,但页框被回收,换出至磁盘(交换区)。3.引用的内存页,在进程空间之外,不属于该进程,可能已被free()。我们使用一段伪代码来大致了解缺页异常。

/* @filename: example_2_5.c */
…  
demo()  
{  
    char *p;  
    //分配了100Kbytes线性地址  
    if ((p = malloc(1024*100)) != NULL)  // L0  
    {  
        *p = ‘t’;     // L1  
    … //过去了很长一段时间,不管系统忙否,长久不用的页框都有可能被回收  
    *p = ‘m’;      // L2  
    p[4096] = ‘p’;   // L3  
    …  
    free(p);  //L4  
    if (p == NULL)  
    {  
        *p = ‘l’; // L5  
    }  
    }  
}  
…

本文URL地址:http://www.bianceng.cn/OS/Linux/201410/45418.htm

(编辑:佛山站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读