• malloc,free简单的实现


    有关标准库首先简要malloc其原理:
        标准库内部通过一个双向链表。管理在堆中动态分配的内存。
        malloc函数分配内存时会附加若干(一般是12个)字节,存放控制信息。
        该信息一旦被意外损坏,可能在兴许操作中引发异常。


    mmap/munmap   底层不维护不论什么东西,仅仅是返回一个首地址,所分配内存位于堆中



    brk/sbrk   底层维护一个指针,记录所分配的内存结尾,所分配内存位于堆中,底层调用mmap/munmap。

    malloc   底层维护一个双向链表和必要的控制信息,不可越界訪问。所分配内存位于堆中,底层调用brk/sbrk。

    每一个进程都有4G的虚拟内存空间。虚拟内存地址仅仅是一个数字,并没有和实际的物理内存相关联。


    所谓内存分配与释放,其本质就是建立或取消虚拟内存和物理内存间的映射关系


    几个用到的函数:
    void* sbrk (
        intptr_t  increment // 内存增量(以字节为单位)
    );
    返回上次调用brk/sbrk后的末尾地址,失败返回-1。
    increment取值:

    0 - 获取末尾地址。

    >0 - 添加内存空间。

    <0 - 释放内存空间。

    内部维护一个指针。指向当前堆内存最后一个字节的下一个位置。


    sbrk函数依据增量參数调整该指针的位置,同一时候返回该指针原来的位置。


    若发现页耗尽或空暇。则自己主动追加或取消页映射


    int brk (
       void* end_data_segment // 内存块末尾地址
    );

    成功返回0。失败返回-1



    内部维护一个指针,指向当前堆内存最后一个字节的下一个位置。
    brk函数依据指针參数设置该指针的位置。
    若发现页耗尽或空暇。则自己主动追加或取消页映射。


    sbrk/brk底层维护一个指针位置,以页(4K)为单位分配和释放虚拟内存。


    简便起见,可用sbrk分配内存。用brk释放内存



    #include <stdio.h>
    #include <unistd.h>
    #include <stdbool.h>
    typedef struct mem_control_block //内存控制块
    {
    	bool free;   //自由标志
    	struct mem_control_block* prev;  //前向指针
    	size_t size;   //块大小
    }MCB;
    MCB* g_top;  //内存栈顶指针
    
    // +----------------------+              g_top
    // v                      |                |
    // +------+------------+--|---+------------+------+------------+
    // | prev |            | prev |            | prev |            |
    // | free |            | free |            | free |            |
    // | size |            | size |            | size |            |
    // +------+------------+------+------------+------+------------+
    //   MCB  |<-- size -->|
    
    void* my_malloc(size_t size)
    {
    	MCB* mcb;
    	for(mcb = g_top; mcb; mcb = mcb->prev)
    		if(mcb->free && mcb->size >= size)//寻找可用空块
    			break;
    	if(!mcb) //假设没有可用空块
    	{
    		mcb = sbrk(sizeof(MCB) + size); //增量分配size大小内存
    		if(mcb == (void*)-1)    //假设分配失败,打印错误信息
    		{
    			perror("sbrk");
    			return NULL;
    		}
    		mcb->prev = g_top; //调整前向指针
    		mcb->size = size;  //大小
    		g_top = mcb;    //调整栈顶指针
    	}
    	mcb->free = false;  //不管用原来空块还是新分配的块,都标记为不可用
    	return mcb + 1; //返回实际分配的内存起始地址
    }
    void my_free(void* ptr)
    {
    	if(!ptr)
    		return;
    
    	MCB* mcb = (MCB*)ptr - 1;  //取控制块起始地址,
    				//注意:ptr为实际可用内存起始地址
    	mcb->free = true;   //块标记为可用
    	
    	//在栈中查找连续内存块
    	for(mcb = g_top; mcb->prev; mcb = mcb->prev)
    		if(!mcb->free)
    			break;
    	//释放整个栈全部内存块
    	if(mcb->free)
    	{
    		g_top = mcb->prev;
    		brk(mcb);   //改动内存块末尾地址
    	}
    	else  //释放连续的标记为true的内存块
    	{
    		g_top = mcb;
    		brk((void*)mcb + sizeof(MCB) + mcb->size);
    	}
    }
    //測试
    int main(void)
    {
    	int* pa[10];
    	size_t size = sizeof(pa) / sizeof(pa[0]), i, j;
    	for(i = 0; i < size; ++i)
    	{
    		if(!(pa[i] = (int*)my_malloc((i+1) * sizeof(int))))
    		{
    			perror("my_malloc");
    			return -1;
    		}
    		for(j = 0; j <= i; ++j)
    			pa[i][j] = j;
    	}
    	for(i = 0; i < size; ++i)
    	{
    		for(j = 0; j <= i; ++j)
    			printf("%d ", pa[i][j]);
    		printf("
    ");
    	}
    	for(;;)
    	{
    		my_free(pa[--i]);
    		if(! i)
    			break;
    	}
    	return 0;
    }
    


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    Windows10安装Oracle19c数据库详细记录(图文详解)
    构建 FTP 文件传输服务器
    构建 Samba 文件共享服务器
    Linux磁盘配额(xfs)
    Linux配置磁盘配额(ext4)
    Linux 制作ISO镜像
    Linux磁盘分区
    用户和文件权限管理命令的使用(实验)
    CentOS7 配置yum源
    VMware CentOS 7 安装(vmware的版本15.5)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4800515.html
Copyright © 2020-2023  润新知