glibc中的内存管理采用的是ptmalloc机制,其malloc和free函数操作的是进程虚拟地址空间。
malloc分配内存是通过brk(sbrk)
和mmap
这两个系统调用实现的,brk(sbrk)通过移动进程地址空间的heap顶部指针向地址增大/缩小方向移动,mmap是在进程地址空间的heap和stack中间分配虚拟地址空间。
不管使用的是哪种内存分配方式,仅仅都是操作虚拟地址空间,并没有实际物理内存的分配,只有当进程需要访问该虚拟地址空间时,发生缺页中断才会实际分配物理内存并建立映射关系。
对于内存释放free而言,由brk(sbrk)分配的内存并不一定会真正释放,默认情况下,只有当heap最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,才会执行内存紧缩操作(trim)释放内存。即使没有真正释放,当应用程序再次请求内存并且之前free的内存大小满足请求条件时可以直接返回给应用程序再次使用。
mmap分配的内存在free时会真正释放。
具体实现可以参看https://blog.csdn.net/just_lion/article/details/80592027
以下是示例程序:
一,sbrk内存分配模式,(单次分配<128k)
1)分配2048个64k大小的内存
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define chunk_size 64*1024
#define chunk_num 2048
void* chunk_array[chunk_num];
int main(void)
{
int i,j;
for (i=0; i<chunk_num; i++)
{
chunk_array[i] = malloc(chunk_size);
for(j =0; j<chunk_size; j++)
{
*((char*)chunk_array[i] + j) = '\0';
}
}
sleep(20000);
return 0;
}
此时通过top -p <pid>查看内存占用为:
其中VIRT为虚拟内存占用, RES为物理内存占用。
2) 从heap底部(低地址)执行部分free
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define chunk_size 64*1024
#define chunk_num 2048
void* chunk_array[chunk_num];
int main(void)
{
int i,j;
for (i=0; i<chunk_num; i++)
{
chunk_array[i] = malloc(chunk_size);
for(j =0; j<chunk_size; j++)
{
*((char*)chunk_array[i] + j) = '\0';
}
}
for (i=0; i<chunk_num-10; i++)
{
free(chunk_array[i]);
}
sleep(20000);
return 0;
}
此时查看内存占用,没有任何内存释放,因为heap顶部没有释放。
3) 从heap顶部(高地址)执行部分free
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define chunk_size 64*1024
#define chunk_num 2048
void* chunk_array[chunk_num];
int main(void)
{
int i,j;
for (i=0; i<chunk_num; i++)
{
chunk_array[i] = malloc(chunk_size);
for(j =0; j<chunk_size; j++)
{
*((char*)chunk_array[i] + j) = '\0';
}
}
for (i=chunk_num-1; i>10; i--)
{
free(chunk_array[i]);
}
sleep(20000);
return 0;
}
查看内存占用:
此时内存基本释放完毕。
二,mmap内存分配模式,(单次分配>=128k)
1) 分配2048个128k大小的内存
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define chunk_size 128*1024
#define chunk_num 2048
void* chunk_array[chunk_num];
int main(void)
{
int i,j;
for (i=0; i<chunk_num; i++)
{
chunk_array[i] = malloc(chunk_size);
for(j =0; j<chunk_size; j++)
{
*((char*)chunk_array[i] + j) = '\0';
}
}
sleep(20000);
return 0;
}
此时内存占用为:
2) 从低地址执行部分free
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define chunk_size 128*1024
#define chunk_num 2048
void* chunk_array[chunk_num];
int main(void)
{
int i,j;
for (i=0; i<chunk_num; i++)
{
chunk_array[i] = malloc(chunk_size);
for(j =0; j<chunk_size; j++)
{
*((char*)chunk_array[i] + j) = '\0';
}
}
for (i=0; i<chunk_num-10; i++)
{
free(chunk_array[i]);
}
sleep(20000);
return 0;
}
此时查看内存占用:
可见内存基本释放完毕。