精华内容
下载资源
问答
  • 内存管理通过什么实现
    千次阅读
    2018-07-21 16:00:53

    模拟内存管理设计与实现:
    模拟实现动态分区内存管理机制。设计和实现关于内存管理的内存布局初始化及内存申请分配、内存回收等基本功能操作函数,尝试对 256MB 的用户内存空间进行动态分区方式模拟管理。内存分配的基本单位为 1KB,同时要求支持至少两种分配策略,并进行测试和对不同分配策略的性能展开比较评估。要求随机发生进程创建事件(包括进程运行时间及申请内存空间大小)。

        首次适应(First Fit)算法:空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。 

        最佳适应(Best Fit)算法:空闲分区按容量递增形成分区链,找到第一个能满足要求的空闲分区。 

        最坏适应(Worst Fit)算法:又称最大适应(Largest Fit)算法,空闲分区以容量递减的次序链接。找到第一个能满足要求的空闲分区,也就是挑选出最大的分区。

    // 模拟内存管理.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    
    
    typedef unsigned long DIZHI;  //地址类型的设置
    
    int num = 0;  //进程数量
    int c;  //选择算法
    int times = 0;  //查找次数
    
    typedef struct freenode {  //空闲内存链表
    	int size;  //空闲地址块的大小
    	int address;  //起始地址
    	struct freenode* next;  //指向下一个空闲地址块
    };
    freenode *free_L = NULL;  //空闲链表
    
    struct busynode {  //内存占用链表
    	int pid;  //进程号
    	int size;  //地址块的大小
    	int address;  //起始地址
    	struct busynode* next;  //指向下一个被占用的地址块
    };
    busynode* busy_L = NULL;  //进程内存链表
    
    
    /*设计一定的数据结构以描述256MB内存空间的使用状况,并设计和构建函数void ChuShuHuaNC
    实现内存布局的初始化。假定内存空间的低址部分56MB(即0~56M-1)作为系统区和不参与分配过程。*/
    void ChuShiHuaNC(DIZHI zKS_KYNC, DIZHI zJS_KYNC)
    {
    	struct freenode *p;
    	busy_L = (busynode*)malloc(sizeof(busynode));
    	free_L = (freenode*)malloc(sizeof(freenode));
    	p = (freenode*)malloc(sizeof(freenode));
    
    	busy_L->next = NULL;  //初始化占用地址块链表
    	free_L->next = p;  //初始化空闲地址链表
    	p->size = zJS_KYNC - zKS_KYNC;  //空闲区的大小
    	p->address = zKS_KYNC;  //0~55不参与内存分配过程
    	printf("内存空间(%d~%dM)参与实际分配过程\n",zKS_KYNC,zJS_KYNC);
    	p->next = NULL;
    }
    
    void FF() {
    	freenode* fbh = free_L->next;
    	freenode* fbp = free_L->next;
    	int sizep;
    	int addrp;
    	while (fbh != NULL) {
    		while (fbp->next != NULL) {
    			if (fbp->address>fbp->next->address) {
    				addrp = fbp->address;
    				fbp->address = fbp->next->address;
    				fbp->next->address = addrp;
    				sizep = fbp->size;
    				fbp->size = fbp->next->size;
    				fbp->next->size = sizep;
    			}
    			fbp = fbp->next;
    		}
    		fbp = free_L->next;
    		fbh = fbh->next;
    	}
    	while (fbh != NULL) {
    		printf("%d,%d", fbh->size, fbh->address);
    		fbh = fbh->next;
    	}
    }
    
    void BF() {
    	freenode* fbh = free_L->next;
    	freenode* fbp = free_L->next;
    	int sizep;
    	int addrp;
    	while (fbh != NULL) {
    		while (fbp->next != NULL) {
    			if (fbp->size > fbp->next->size) {
    				addrp = fbp->address;
    				fbp->address = fbp->next->address;
    				fbp->next->address = addrp;
    				sizep = fbp->size;
    				fbp->size = fbp->next->size;
    				fbp->next->size = sizep;
    			}
    			fbp = fbp->next;
    		}
    		fbp = free_L->next;
    		fbh = fbh->next;
    	}
    	while (fbh != NULL) {
    		printf("%d,%d", fbh->size, fbh->address);
    		fbh = fbh->next;
    	}
    }
    
    void WF() {
    	freenode* fbh = free_L->next;
    	freenode* fbp = free_L->next;
    	int sizep;
    	int addrp;
    	while (fbh != NULL) {
    		while (fbp->next != NULL) {
    			if (fbp->size<fbp->next->size) {
    				addrp = fbp->address;
    				fbp->address = fbp->next->address;
    				fbp->next->address = addrp;
    				sizep = fbp->size;
    				fbp->size = fbp->next->size;
    				fbp->next->size = sizep;
    			}
    			fbp = fbp->next;
    		}
    		fbp = free_L->next;
    		fbh = fbh->next;
    	}
    	while (fbh != NULL) {
    		printf("%d,%d", fbh->size, fbh->address);
    		fbh = fbh->next;
    	}
    }
    
    /*设计和实现内存申请分配函数DIZHI ShenQingNC(unsigned long zDX),内存分配的基本单位为1KB,
    同时要求支持至少两种分配策略(如首次适应、循环首次适应、最佳适应、最坏适应等),若分配失败则返回NULL。*/
    DIZHI ShenQingNC(unsigned long zDX)
    {
    	printf("\n创建新的进程:所需空间为%d\n",zDX);
    
    	busynode *b = (busynode*)malloc(sizeof(busynode));
    	busynode *a = (busynode*)malloc(sizeof(busynode));
    
    	switch (c){
    	case 1: FF(); 
    		break;
    	case 2: BF(); 
    		break;
    	case 3: WF(); 
    		break;
    	default: printf("输入错误!\n"); 
    		return NULL;
    	}
    	freenode *p = free_L->next;
    	while (p != NULL)
    	{
    		if (p->size >= zDX)
    		{
    			a->next = busy_L->next;
    			busy_L->next = a;
    			
    			num++;  //进程数量增加
    			p->size -= zDX;
    			a->size = zDX;
    			a->address = p->address;
    			p->address = p->address + a->size;
    			printf("将首地址为%d,大小为%d的内存空间分配给进程!\n\n", a->address, a->size);
    			return 1;
    		}
    		p = p->next;
    		times++;
    	}
    	printf("内存空间不足!\n");
    	free(a);
    	return 0;
    }
    
    /*设计和实现内存回收函数void HuiShouNC(DIZHI zKSDZ) ,若回收分区与其它空闲分区相邻接,则采取合并措施。*/
    void HuiShouNC(DIZHI zKSDZ)
    {
    	int i = 0;
    	int m = rand()%num;  //随机指定进程号
    	busynode *b = (busynode*)malloc(sizeof(busynode)),
    		*c = (busynode*)malloc(sizeof(busynode));
    	printf("回收进程%d所分配的内存\n",m);
    	c = busy_L;
    	b = c->next;
    	while (b != NULL)
    	{
    		if (i == m)
    			break;
    		i++;
    		c = b;
    		b = b->next;
    	}
    	if (b->size == NULL)
    	{
    		printf("指定进程时出错!\n");
    		return;
    	}
    	else
    	{
    		c->next = b->next;  //回收算法 完成地址块的合并
    		
    		num--;
    		freenode *t = (freenode*)malloc(sizeof(freenode));
    		t->next = free_L->next;
    		free_L->next = t;
    		t->size = b->size;
    		t->address = b->address;
    		free(b);
    		printf("回收完成!\n");
    		FF();  //地址递增排序
    		freenode *p,*q;
    		q = free_L->next;
    		p = q->next;
    		while (p != NULL)   //合并内存
    		{
    			if (q->address + q->size == p->address)
    			{
    				printf("合并地址为%d和%d的空间!\n",q->address,p->address);
    				q->size += p->size;
    				q->next = p->next;
    				free(p);
    				p = q->next;
    				continue;
    			}
    			q = p;
    			p = p->next;
    		}
    	}
    }
    void display_memory()
    {
    	int s = 0;
    	busynode *a;
    	a = busy_L->next;
    	printf("\n----------------------------\n");
    	while (a != NULL)
    	{
    		printf("进程%d:起始地址为%d,大小为%d\n",s++,a->address,a->size);
    		a = a->next;
    	}
    	printf("----------------------------\n\n");
    }
    int main()
    {
    	printf("地址分配实验:\n");
    	printf("初始化内存空间:(%d~%dM)\n",0,256);
    	ChuShiHuaNC(56,256);  //初始化内存空间,0~56M-1不参与分配过程
    
    	printf("选择分配策略: 1.FF 2.BF 3.WF\n");
    	scanf("%d", &c);
    /*基于不同的内存分配策略形成不同版本的内存管理器,并根据内存平均利用率和
    分配查找分区比较次数等指标展开测试和对不同分配策略的内存管理器性能进行评估。*/
    	double aver = 0;  //平均内存利用率
    	int x = 0;
    	double size = 0;
    	int tag = 0;
    	while(1)
    	{
    		display_memory();
    //		Sleep(3000);
    		if (num>0)  //产生随机数,并根据该值确定是申请内存还是回收内存
    		{
    			int ss = rand() % 7;
    			if (ss%2 == 0)
    			{
    				int m = rand()%80;
    				if (m != 0)
    				{
    					ShenQingNC(m);
    					size += m;
    					tag++;
    				}
    			}
    			else
    			{
    				int n = rand() % num;
    				HuiShouNC(n);
    			}
    		}
    		else
    		{
    			int m = rand() % 80;
    			if (m != 0)
    			{
    				ShenQingNC(m);
    				size += m;
    				tag++;
    			}
    		}
    		//性能指标计算:内存平均利用率&&查找次数
    		//计算内存平均利用率
    		busynode *it = busy_L->next;
    		double P = 0;
    		while (it != NULL)
    		{
    			P += it->size;
    			it = it->next;
    		}
    		printf("内存利用率:%.3f\n",P/200);
    		x++;
    		aver += P/200;
    		if (x == 10000)
    			break;
    	}
    	printf("\n该方法平均内存申请大小:%.3f,平均内存利用率:%.3f,查找次数:%d\n",size/tag, aver/x ,times);
    	return 0;
    }
    
    更多相关内容
  • 内存管理算法实现

    千次阅读 2016-11-03 21:08:45
    在上一节,我们得知可用内存的大小后,我们就可以开发一个简单的管理算法去管理和分配可用用内存

    本节代码的调试和实现过程可参看视频:
    Linux kernel Hacker, 从零构建自己的内核

    在上一节,我们得知可用内存的大小后,我们就可以开发一个简单的管理算法去管理和分配可用用内存。

    首先创建一个头文件mem_util.h,用来定义内存管理模块相关的数值,变量和接口:

    #define  MEMMAN_FREES  4096
    
    struct FREEINFO {
        unsigned int addr, size;
    };
    
    struct MEMMAN {
        int frees, maxfrees, lostsize, losts;
        struct FREEINFO free[MEMMAN_FREES];
    };
    
    void memman_init(struct MEMMAN *man);
    
    unsigned int memman_total(struct MEMMAN *man);
    
    unsigned int memman_alloc(struct MEMMAN *man, unsigned int size);
    
    int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size);
    
    

    FREEINFO 结构用来表示可用内存的起始地址和大小,MEMMAN 表示内存管理器,其中的frees 表示当前可用内存对应的FREEINO结构体有多少个,maxfrees 表示我们的内存管理器最多可以容纳多少个可用内存片,一个可用内存片就是一个FREEINFO结构体。当有内存释放时,有些释放后的内存块无法重现加入内存管理器,这些内存块就得丢掉,那么lostsize 就用来记录,内存管理器总共放弃了多少内存碎片,losts记录的是碎片的数量。

    memman_init 用来初始化内存管理区结构体,memman_total用来计算一个内存管理区存储着多少可用的内存,memman_alloc 用来从指定的内存管理器对象中获取可用内存,memman_free 则用于释放不再需要的内存片。

    我们再看看相关实现(mem_util.c):

    #include "mem_util.h"
    
    void memman_init(struct MEMMAN *man) {
        man->frees = 0;
        man->maxfrees = 0;
        man->lostsize = 0;
        man->losts = 0;
    }
    
    unsigned int memman_total(struct MEMMAN *man) {
        unsigned int i, t = 0;
        for (i = 0; i < man->frees; i++) {
            t += man->free[i].size;
        }
    
        return t;
    }
    
    unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) {
        unsigned int i, a;
        for (i = 0; i < man->frees; i++) {
            if (man->free[i].size >= size) {
                a = man->free[i].addr;
                man->free[i].size -= size;
                if (man->free[i].size == 0) {
                    man->frees--;
                }
    
                return a;
            }
        }
    
        return 0;
    }
    
    int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) {
        int i, j;
        for (i = 0; i < man->frees; i++) {
            if (man->free[i].addr > addr) {
                break;
            }
        }
    
        if (i > 0) {
            if (man->free[i-1].addr + man->free[i-1].size == addr) {
               man->free[i-1].size += size;
               if (i < man->frees) {
                   if (addr + size == man->free[i].addr) {
                       man->free[i-1].size += man->free[i].size;
                       man->frees--;
                   }
               }
    
               return 0;
            }
        }
    
        if (i < man->frees) {
            if (addr + size == man->free[i].addr) {
               man->free[i].addr = addr;
               man->free[i].size += size;
               return 0;
            }
        }
    
        if (man->frees < MEMMAN_FREES) {
            for (j = man->frees; j > i; j--) {
                man->free[j] = man->free[j-1];
            }
    
            man->frees++;
            if (man->maxfrees < man->frees) {
                man->maxfrees = man->frees;
            }
    
            man->free[i].addr = addr;
            man->free[i].size = size;
            return 0;
        }
    
        man->losts++;
        man->lostsize += size;
        return -1;
    }
    

    头三个函数逻辑比较简单,复杂的是内存释放时的处理逻辑。当有内存释放的时候,我们需要把释放内存的起始地址和大小作为参数传入。假定我们要释放的内存片起始地址是 0x200, 大小是0x100, 如果内存管理对象中存在着一片可用内存,起始地址是0x100, 长度为0x100, 那么当前释放的内存片就可以跟原有可用内存合并,合并后的内存块就是起始地址为0x100, 长度为0x200的一片内存块。

    如果内存管理对象不但含有起始地址为0x100, 长度为0x100的内存片,而且还含有起始地址为0x300, 长度为0x100的内存片,这样的话,三块内存片就可以合并成一块内存,也就是起始地址为0x100, 长度为0x300的一个大块内存片。

    这就是代码if( i > 0) {….} 这个模块的逻辑。

    如果不存在上面的情况,比如当前内存管理模块存在的内存块是其实地址为0x100, 长度为0x50, 另一块内存块起始地址是0x350, 长度为0x100:
    FREEINFO{ addr : 0x100; size : 0x50;};
    FREEINFO{addr: 0x350; size: 0x100};

    这样的话,我们就构建一个对应于要释放内存的FREEINFO对象,然后把这个对象插入到上面两个对象之间:
    FREEINFO{ addr : 0x100; size : 0x50;};

    FREEINFO{addr: 0x200; size: 0x100};

    FREEINFO{addr: 0x350; size: 0x100};

    这就是对应于if (i < man->frees){…} 这个分支的主要逻辑。

    如果当前所有可用内存的起始地址都大于要释放的内存块,则将释放的内存块插到最前面,例如当前可用内存块为:

    FREEINOF {addr: 0x350; size: 0x100;}
    FREEINFO {addr: 0x460; size: 0x100;}

    那么释放起始地址为0x200的内存块后,情况如下:

    FREEINFO{addr: 0x200; size: 0x100;}
    FREEINOF {addr: 0x350; size: 0x100;}
    FREEINFO {addr: 0x460; size: 0x100;}

    或者如果当前释放的内存块起始地址大于所有可用内存块,例如要释放的内存块起始地址是0x450, 其他可用的内存块起始地址分别是0x100, 0x300, 那么释放的内存块则添加到末尾:
    FREEINFO{addr: 0x100; size: 0x100;}
    FREEINOF {addr: 0x350; size: 0x50;}
    FREEINFO {addr: 0x450; size: 0x100;}

    这就是 if (man->frees < MEMMAN_FREES) {…} 的实现逻辑。

    如果以上情况都不满足的话,那么当前回收的内存块则直接丢弃。

    一般而言,操作系统的内存算法不可能如此简单,内存分配算法是系统内核最为复杂的模块之一,我们当前先从简单入手,后面在慢慢引入分页机制,实现更复杂的内存管理算法。

    由于当前内存管理模块与原来C语言实现的模块是分开的,因此它们需要单独编译,然后再把两个编译好的 .o 文件合并成一个模块,编译过程如下:

    1: 先使用命令编译mem_util.c
    gcc -m32 -fno-asynchronous-unwind-tables -s -c -o mem_util.o mem_util.c

    2: 再使用命令编译原来的C语言模块:
    gcc -m32 -fno-asynchronous-unwind-tables -s -c -o write_vga_desktop.o write_vga_desktop.c

    3:把两个编译好的模块链接成一个模块:
    ld -m elf_i386 -r write_vga_desktop.o mem_util.o -o ckernel.o

    4:把ckernel.o 反汇编,然后再添加到内核的汇编模块中一起编译:
    ./objconv -fnasm ckernel.o ckernel.asm

    把上面所以步骤完成后,执行效果如下:
    这里写图片描述

    从显示出的信息看,虚拟机总内存是1G, 3FE MB 等于 1022M, 也就是说可用内存为1022M.

    有了内存管理机制后,我们后面可以在此基础上,实现图层叠加管理,也就是窗口相互叠加时,互不影响,要实现这种功能,就需要为每个窗口分配相应的内存以便在叠加时能够互不影响。

    展开全文
  • C / C++ 内存管理

    千次阅读 多人点赞 2022-05-27 09:35:36
    2、C语言中动态内存管理方式 malloc / calloc / realloc / free 3、C++内存管理方式 new / delete 操作内置类型 new / delete 操作自定义类型 4、operator new与operator delete函数(重要点进行讲解) ...

    目录

    1、C / C++内存分布

    2、C语言中动态内存管理方式

            malloc / calloc / realloc / free

    3、C++内存管理方式

            new / delete 操作内置类型

            new / delete 操作自定义类型

    4、operator new与operator delete函数(重要点进行讲解)

            operator new与operator delete函数(重点)

            operator new与operator delete的类专属重载(了解)

    5、new和delete的实现原理

            内置类型

            自定义类型

    6、定位new表达式(placement-new) (了解)

    7、常见面试题

            7.1、malloc/free和new/delete的区别

            7.2、内存泄漏

                    什么是内存泄漏,内存泄漏的危害

                    内存泄漏分类(了解)

                    如何检测内存泄漏(了解)

                    如何避免内存泄漏

            7.3、如何一次在堆上申请4G的内存?


    1、C / C++内存分布

    我们先来看下面的一段代码和相关问题

    int globalVar = 1;
    static int staticGlobalVar = 1;
    void Test()
    {
    	static int staticVar = 1;
    	int localVar = 1;
    	int num1[10] = { 1, 2, 3, 4 };
    	char char2[] = "abcd";
    	const char* pChar3 = "abcd";
    	int* ptr1 = (int*)malloc(sizeof(int) * 4);
    	int* ptr2 = (int*)calloc(4, sizeof(int));
    	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
    	free(ptr1);
    	free(ptr3);
    }

    来看看如下的几个问题:

    1. 选择题:
    选项: A.栈 B.堆 C.数据段 D.代码段
    globalVar在哪里?__C__ staticGlobalVar在哪里?__C__
    staticVar在哪里?__C__ localVar在哪里?__A__
    num1 在哪里?__A__
    char2在哪里?__A__ *char2在哪里?__A__
    pChar3在哪里?__A__ *pChar3在哪里?__D__
    ptr1在哪里?__A__ *ptr1在哪里?__B__
    
    2. 填空题:
    sizeof(num1) = __40__;
    sizeof(char2) = __5__; strlen(char2) = __4__;
    sizeof(pChar3) = __4/8__; strlen(pChar3) = __4__;
    sizeof(ptr1) = __4/8__;

    其实这部分内容在C语言的时候我已经讲解过,这里给出博客链接C/C++内存分配

    这里给出一幅图:

     C/C++程序内存分配的几个区域:

    • 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
    • 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。
    • 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
    • 代码段:存放函数体(类成员函数和全局函数)的二进制代码。

    想看更多这方面练习的小伙伴可以点击这个链接:sizeof 、strlen 内存分配练习


    2、C语言中动态内存管理方式

    malloc / calloc / realloc / free

    这部分内容我在C语言的博客中有详细全面的讲解,可以点击这块链接查看:C语言动态内存管理

    这边给出代码演示:

    void Test()
    {
    	int* p1 = (int*)malloc(sizeof(int));
    	free(p1);
    	int* p2 = (int*)calloc(4, sizeof(int));
    	free(p2);
    	int* p3 = (int*)realloc(p2, sizeof(int) * 10);
    	free(p3);
    }
    • malloc:

    在内存的动态存储区中分配一块长度为size字节的连续区域,参数size为需要内存空间的长度,返回该区域的首地址

    • calloc:

    与malloc相似,不过函数calloc() 会将所分配的内存空间中的每一位都初始化为零

    • realloc:

     给一个已经分配了地址的指针重新分配空间,可以做到对动态开辟内存大小的调整。

    • 【面试题】:malloc/calloc/realloc的区别?

    1. 函数malloc不能初始化所分配的内存空间,而函数calloc能.如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之, 如果这部分内存曾经被分配过,则其中可能遗留有各种各样的数据.也就是说,使用malloc()函数的程序开始时(内存空间还没有被重新分配)能正常进行,但经过一段时间(内存空间还已经被重新分配)可能会出现问题.
    2. 函数calloc() 会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为0;如果你是为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针;
    3. 函数malloc向系统申请分配指定size个字节的内存空间.返回类型是 void类型.void表示未确定类型的指针.C,C++规定,void* 类型可以强制转换为任何其它类型的指针.
    4. realloc可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变.当然,对于缩小,则被缩小的那一部分的内容会丢失.realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址.相反,realloc返回的指针很可能指向一个新的地址.
    5. realloc是从堆上分配内存的.当扩大一块内存空间时,realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,此时即原地扩;如果数据后面的字节不够,那么就使用堆上第一个有足够大小的自由块,现存的数据然后就被拷贝至新的位置,而老块则放回到堆上.这句话传递的一个重要的信息就是数据可能被移动,即异地扩

    3、C++内存管理方式

    C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过newdelete操作符进行动态内存管理

    new / delete 操作内置类型

    void Test()
    {
    	// new一个int类型的空间
    	int* ptr4 = new int;
    	// new一个int类型的空间并初始化为10
    	int* ptr5 = new int(10);
    	// new10个int类型的空间
    	int* ptr6 = new int[10];
    	// new10个int类型的空间并初始化
    	int* ptr7 = new int[10]{ 10,9,8,7,6,5 }; //跟数组的初始化很像,大括号有几个,初始化几个,其余为0。不过C++11才支持的语法
    	delete ptr4;
    	delete ptr5;
    	delete[] ptr6;
    	delete[] ptr7;
    }
    

    注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[ ]和delete[ ]

    总结:对于内置类型而言,用malloc和new,除了用法不同,没有什么区别。它们的区别在于自定义类型

    new / delete 操作自定义类型

    先给出结论:

    • 申请空间时:malloc只开空间,new既开空间又调用构造函数初始化。
    • 释放空间时:delete会调用析构函数,free不会

    先看下malloc和free:

    很明显,malloc的对象只是开辟了空间,并没有初始化,free后也只是普通的释放。

    再看下new和delete:

    当我们运行程序时,结果如下:

    很明显,使用new,既可以开辟空间,又调用了构造函数从而完成初始化,而delete时调用了析构函数,以此释放空间。

    在我们先前学习的链表中,C语言为了创建一个节点并将其初始化,需要单独封装一个函数进行初始化,我C++只需要用new即可开空间+初始化:

    struct ListNode
    {
    	struct ListNode* _next;
    	int _val;
        //构造函数
    	ListNode(int val = 0) 
    		:_next(nullptr)
    		,_val(val)
    	{}
    };
    int main()
    {
    	ListNode* n2 = new ListNode(10); //C++的new相当于我之前的BuyListNode函数
    	return 0;
    }

    如若只是单纯的区分malloc和new,那么malloc纯粹只开空间不初始化,而new既开空间又初始化。

    总结:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

    • new和malloc还有一个区别就是在申请内存失败时的处理情况不同。

    malloc如若开辟内存失败,会返回空指针这个我们都晓得的,但是new失败抛异常

    仔细观察下面这段代码:

    int main()
    {
        //malloc失败,返回空指针
    	int* p1 = (int*)malloc(sizeof(int) * 10);
    	assert(p1); //malloc出来的p1需要检查合法性
        //new失败,抛异常
    	int* p2 = new int;
    	//new出来的p2不需要检查合法性
    }

    为了演示malloc和new在开辟内存时失败的场景,这里给出一份测试:

    int main()
    {
    	void* p3 = malloc(1024 * 1024 * 1024); //1G
    	cout << p3 << endl;
    	void* p4 = new char[1024 * 1024 * 1024];
    	cout << p4 << endl;
    }

    换个顺序看看:

    此段测试充分说明了我先开辟1G的大小是没有问题的,但是再开辟1个G的大小就会报错了,为了能够看出malloc和new均报错的场景,我们再定义一个指针占据这1G:

    此段测试更能够清楚的看出mallloc失败会返回空指针,而new失败会抛异常。 对于抛异常,我们理应进行捕获,不过这块内容我后续会讲到,这里先给个演示:


    4、operator new与operator delete函数(重要点进行讲解)

    operator new与operator delete函数(重点)

    newdelete是用户进行动态内存申请和释放的操作符operator newoperator delete是系统提供的全局函数new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

    • 注意:operator new和operator delete不是对new和delete的重载,这是俩库函数。

    源码链接:operator new、operator delete

    operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。operator new本质是封装了malloc。operator delete本质是封装了free。

    • 具体使用operator new和operator delete的操作如下:
    int main()
    {
    	Stack* ps2 = (Stack*)operator new(sizeof(Stack));
    	operator delete(ps2);
    
    	Stack* ps1 = (Stack*)malloc(sizeof(Stack));
        assert(ps1);
    	free(ps1);
    }

    operator new和operator delete的功能和malloc、free一样。也不会去调用构造函数和析构函数,不过还是有区别的,1、operator new不需要检查开辟空间的合法性。2、operator new开辟空间失败就抛异常

    • operator new和operator delete的意义体现在new和delete的底层原理
    Stack* ps3 = new Stack;
    new的底层原理:转换成调用operator new + 构造函数
    delete ps3;
    delete的底层原理:转换成调用operator delete + 析构函数

    new的底层原理就是转换成调用operator new + 构造函数,我们可以通过查看反汇编来验证:

    delete也是转换成调用operator delete + 析构函数,这里画图演示总结:

    operator new与operator delete的类专属重载(了解)

    为了避免有些情况下我们反复的向堆申请释放空间,于是产生池化技术(内存池),直接找内存池申请释放空间,此时效率更高更快。以后会详细讲解到池化技术,这里简要了解。而上述这俩的类专属重载就是在new调用operator new的时候就可以走内存池的机制从而提高效率。


    5、new和delete的实现原理

    内置类型

    如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间而且new在申请空间失败时会抛异常,malloc会返回NULL

    自定义类型

    new的原理

    1. 调用operator new函数申请空间
    2. 在申请的空间上执行构造函数,完成对象的构造

    delete的原理

    1. 在空间上执行析构函数,完成对象中资源的清理工作
    2. 调用operator delete函数释放对象的空间

    new T[N]的原理

    1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
    2. 在申请的空间上执行N次构造函数

    delete[ ]的原理

    1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
    2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

    6、定位new表达式(placement-new) (了解)

    定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象

    使用格式:

    new (place_address) type或者new (place_address) type(initializer-list)

    place_address必须是一个指针,initializer-list是类型的初始化列表

    使用场景:

    定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化

    class Test
    {
    public:
    	Test(int date = 2)
    		: _data(date)
    	{
    		cout << "Test():" << this << endl;
    	}
    	~Test()
    	{
    		cout << "~Test():" << this << endl;
    	}
    private:
    	int _data;
    };
    int main()
    {
    	// pt现在指向的只不过是与Test对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
    	Test* pt1 = (Test*)malloc(sizeof(Test));
        //new (place_address) type
    	new(pt1)Test; // 注意:如果Test类的构造函数有参数时,此处需要传参
    
        //new(place_address) type(initializer - list)
    	Test* pt2 = (Test*)malloc(sizeof(Test));
    	new(pt2)Test(10);
    }
    

    7、常见面试题

    7.1、malloc/free和new/delete的区别

    共同点:

    • 都是从堆上申请空间,并且需要用户手动释放。

    不同点:

    1. malloc和free是函数,new和delete是操作符
    2. malloc申请的空间不会初始化,new可以初始化
    3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
    4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
    5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常(底层区别)
    6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理(底层区别)

    7.2、内存泄漏

    什么是内存泄漏,内存泄漏的危害

    什么是内存泄漏:

    • 内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。(内存泄漏是指针丢了)

    内存泄漏的危害:

    • 长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死
    void MemoryLeaks()
    {
    	// 1.内存申请了忘记释放
    	int* p1 = (int*)malloc(sizeof(int));
    	int* p2 = new int;
    	// 2.异常安全问题
    	int* p3 = new int[10];
    	Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.
    	delete[] p3;
    }

    内存泄漏分类(了解)

    C/C++程序中一般我们关心两种方面的内存泄漏:

    堆内存泄漏(Heap leak)

    • 堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。

    系统资源泄漏

    • 指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

    如何检测内存泄漏(了解)

    如何避免内存泄漏

    1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
    2. 采用RAII思想或者智能指针来管理资源。
    3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
    4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。

    总结一下:

    • 内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。

    7.3、如何一次在堆上申请4G的内存?

    // 将程序编译成x64的进程,运行下面的程序试试?
    #include <iostream>
    using namespace std;
    int main()
    {
    	void* p = new char[0xfffffffful];
    	cout << "new:" << p << endl;
    	return 0;
    }

    展开全文
  • 【FreeRTOS】内存管理

    千次阅读 2022-03-29 09:16:34
    总结 FreeRTOS将内核语内存管理分开实现,内核只规定了必要的内存管理函数原型,但不关心这些内存管理函数是如何实现的。这样的方案大大提高了系统的灵活性:不同的应用场景使用不同的内存管理算法。比如对于安全型...

    在介绍本文之前,向大家推荐个非常容易入门的人工智能学习网站,建议点击收藏❤️

    概述

    内存管理对应用程序和操作系统来说都非常重要。现在很多的程序漏洞和运行崩溃都和内存分配使用错误有关。FreeRTOS官方提供了5种内存管理解决方案,这里的内存一般情况下指的是RAM,主要是针对使用者可以针对不同的应用场景使用一种或同时使用多种。在同时使用多种内存管理方案时,可以将原生的API重命名,然后分别初始化,初始化的时候注意要链接不同的内存块。学习RTOS内存管理的时候要先搞清楚它的字节对齐是怎么实现的,这会对看源码有很大帮助。
    在这里插入图片描述

    heap_1.c

    在系统中定义个大数组,内存管理实际就是在这个数组里面操作。这种内存管理方案不会对已申请的内存进行释放。
    在这里插入图片描述
    如上图vPortFree()里面是空操作,这种内存管理方案不对已申请的内存做释放。vPortInitialiseBlocks()是初始化,只对一个剩余内存变量置零,xPortGetFreeHeapSize()是获取剩余内存。下面通过代码注释的形式分析pvPortMalloc()。

    void *pvPortMalloc(size_t xWantedSize)
    {//xWantedSize:需要从大数组中获取的内存大小
    	void *pvReturn = NULL;
    	static uint8_t *pucAlignedHeap = NULL;
    
    /* 确保字节对齐,可以提高CPU访问速度 */
    #if (portBYTE_ALIGNMENT != 1)
    	{
    		if (xWantedSize & portBYTE_ALIGNMENT_MASK)
    		{
    			/* Byte alignment required. */
    			xWantedSize += (portBYTE_ALIGNMENT - (xWantedSize & portBYTE_ALIGNMENT_MASK));
    		}
    	}
    #endif
    
    	vTaskSuspendAll();
    	{
    		if (pucAlignedHeap == NULL)
    		{
    			/* 确保大数组的起始地址的是对齐的,有些是2字节对齐或4字节或8字节或其他,视不同的编译器而定. */
    			pucAlignedHeap = (uint8_t *)(((portPOINTER_SIZE_TYPE)&ucHeap[portBYTE_ALIGNMENT]) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
    		}
    
    		/* 检查是否有足够的空间 */
    		if (((xNextFreeByte + xWantedSize) < configADJUSTED_HEAP_SIZE) &&
    			((xNextFreeByte + xWantedSize) > xNextFreeByte)) /* Check for overflow. */
    		{
    			/* 申请成功后返回申请到的内存起始地址,以及对剩余内存变量做修改. */
    			pvReturn = pucAlignedHeap + xNextFreeByte;
    			xNextFreeByte += xWantedSize;
    		}
    
    		traceMALLOC(pvReturn, xWantedSize);
    	}
    	(void)xTaskResumeAll();
    
    #if (configUSE_MALLOC_FAILED_HOOK == 1)
    	{
    		if (pvReturn == NULL)
    		{//内存申请失败回调函数
    			extern void vApplicationMallocFailedHook(void);
    			vApplicationMallocFailedHook();
    		}
    	}
    #endif
    
    	return pvReturn;
    }
    

    heap_2.c

    这种内存管理方案在heap_1的基础上新增了内存释放的功能,通过链表来现的。
    在这里插入图片描述

    prvHeapInit

    • 内存块初始化
    • 空闲内存列表管理相关初始化话,用于内存释放。申请的次数多了会产生内存碎片。
    static void prvHeapInit(void)
    {
       BlockLink_t *pxFirstFreeBlock;
       uint8_t *pucAlignedHeap;
    
       /* Ensure the heap starts on a correctly aligned boundary. */
       pucAlignedHeap = (uint8_t *)(((portPOINTER_SIZE_TYPE)&ucHeap[portBYTE_ALIGNMENT]) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
    
       /* xStart is used to hold a pointer to the first item in the list of free
       blocks.  The void cast is used to prevent compiler warnings. */
       xStart.pxNextFreeBlock = (void *)pucAlignedHeap;
       xStart.xBlockSize = (size_t)0;
    
       /* xEnd is used to mark the end of the list of free blocks. */
       xEnd.xBlockSize = configADJUSTED_HEAP_SIZE;
       xEnd.pxNextFreeBlock = NULL;
    
       /* To start with there is a single free block that is sized to take up the
       entire heap space. */
       pxFirstFreeBlock = (void *)pucAlignedHeap;
       pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE;
       pxFirstFreeBlock->pxNextFreeBlock = &xEnd;
    }
    

    pvPortMalloc

    void *pvPortMalloc(size_t xWantedSize)
    {
    	//如果是第一次使用本接口要先对该内存管理方案进行初始化
    	//每次申请内存的大小需要加上链表节点大小
    	//空闲内存管理链表的大块内存可能变成小内存
    	//返回可使用的内存的起始地址
    }
    

    vPortFree

    传入的参数往前退一个链表节点大小才能获取到每个节点的信息。

    void vPortFree(void *pv)
    {
    	uint8_t *puc = (uint8_t *)pv;
    	BlockLink_t *pxLink;
    
    	if (pv != NULL)
    	{
    		/* The memory being freed will have an BlockLink_t structure immediately
    		before it. */
    		puc -= heapSTRUCT_SIZE;
    
    		/* This unexpected casting is to keep some compilers from issuing
    		byte alignment warnings. */
    		pxLink = (void *)puc;
    
    		vTaskSuspendAll();
    		{
    			/* Add this block to the list of free blocks. */
    			prvInsertBlockIntoFreeList(((BlockLink_t *)pxLink));
    			xFreeBytesRemaining += pxLink->xBlockSize;
    			traceFREE(pv, pxLink->xBlockSize);
    		}
    		(void)xTaskResumeAll();
    	}
    }
    

    xPortGetFreeHeapSize

    获取剩余内存大小。

    heap_3.c

    这种内存管理方案仅仅是对系统的malloc和free进行封装,做了线程保护。不行要自己分配大数组。
    在这里插入图片描述

    heap_4.c

    该内存管理算法不会产生内存碎片,在内存回收的时候增加了附近的小内存合并的操作。
    内存回收的时候,是按地址大小去遍历的:

    pxPreviousBlock = &xStart;
    pxBlock = xStart.pxNextFreeBlock;
    while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
    {
    	pxPreviousBlock = pxBlock;
    	pxBlock = pxBlock->pxNextFreeBlock;
    }
    

    需要对变量"xBlockAllocatedBit"作特别说明,它的存在使得链表节点头中的xBlockSize包含两种意思,一个是当前内存块的大小,另一个是最高位表示该内存块是否在使用中。

    heap_5.c

    该内存管理算法在heap_4.c的基础上增加了非连续的多个内存块的使用,体现在初始化上面:

    typedef struct HeapRegion
    {
    	uint8_t *pucStartAddress;
    	size_t xSizeInBytes;
    } HeapRegion_t;
    
    HeapRegion_t xHeapRegions[] =
    	{
    		{(uint8_t *)0x80000000UL, 0x10000}, // << Defines a block of 0x10000 bytes starting at address 0x80000000
    		{(uint8_t *)0x90000000UL, 0xa0000}, // << Defines a block of 0xa0000 bytes starting at address of 0x90000000
    		{NULL, 0}							// Terminates the array.
    };
    
    vPortDefineHeapRegions(xHeapRegions);
    

    总结

    FreeRTOS将内核语内存管理分开实现,内核只规定了必要的内存管理函数原型,但不关心这些内存管理函数是如何实现的。这样的方案大大提高了系统的灵活性:不同的应用场景使用不同的内存管理算法。比如对于安全型的嵌入式系统,一般不允许动态内存分配,大都是通过静态分配的。在满足需要的前提下,系统越简单,做得越安全。

    您对FreeRTOS的内存管理有比较好的理解或应用场景吗,欢迎评论区留言

    展开全文
  • 两年前一位同事和我说过,单片机不能实现动态内存管理,两天后我在keil上利用malloc()在coterx m3芯片上实现了一个链表,然后把代码给他看了,对固执的人摆事实好过讲道理。之后我觉得使用malloc()并不能满足我的...
  • 题目:用C语言(也可以用Java)实现采用首次适应算法的内存分配和回收过程。 题目要求: 定义管理空闲分区的相关数据结构:采用空闲分区链表来管理系统中所有的空闲分区,链表中的每个节点表示一个空闲分区,登记有...
  • 你真的了解前端内存管理吗?

    万次阅读 2022-01-23 09:06:57
    往往我们意识里觉得内存管理是后端的事情,单并非如此,前端也需要关注内存使用情况。前端为什么也需要关注内存呢?一方面防止内存占用过大导致页面卡顿,甚至没有响应;另一方面Node.js使用V8引擎,内存管理对于...
  • Android内存管理机制官方详解文档

    千次阅读 2020-12-09 12:40:54
    很早之前写过一篇《Android内存管理机制详解》点击量已7万+,现把Google官方文档整理输出一下,供各位参考。 一、内存管理概览 Android 运行时 (ART) 和 Dalvik 虚拟机使用分页和内存映射来管理内存。这意味着应用...
  • 共享内存原理及实现通信过程

    千次阅读 2022-02-14 09:25:04
    共享内存原理及实现通信过程共享内存的概念及创建过程共享内存的使用函数使用共享内存完成通信 共享内存的概念及创建过程 一. 共享内存的概念 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址...
  • 【面试题】Linux如何实现共享内存

    千次阅读 2019-06-25 10:09:17
    什么实现共享内存? 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享...
  • Android 内存管理机制

    千次阅读 多人点赞 2018-09-03 14:41:45
    Linux的内存管理机制:Android毕竟是基于Linux内核实现的操作系统,因此有必要了解一下Linux的内存管理机制。 Android的内存管理相关知识:Android又不同于Linux,它是一个移动操作系统,因此其内存管理上也有...
  • 3.1.2 操作系统内存管理管些什么

    千次阅读 多人点赞 2020-04-21 20:57:51
    内存空间的扩展(实现虚拟性)3.地址转换三种方式4.内存保护两种方式 0.思维导图 1.内存空间的分配与回收 2.内存空间的扩展(实现虚拟性) 3.地址转换 三种方式 4.内存保护 两种方式 ...
  • 内存管理我的理解是分为两个部分,一个是物理内存的管理,另一个部分是物理内存地址到虚拟地址的转换。 物理内存管理 内核中实现了很多机制和算法来进行物理内存的管理,比如大名鼎鼎的伙伴系统,以及slab分配器等等...
  • 段页式内存管理

    千次阅读 2019-03-18 20:23:54
    一、段页式内存管理的概念   页式存储管理能有效地提高内存利用率,而分段存储管理能反映程序的逻辑结构并有利于段的共享。如果将这两种存储管理方法结合起来,就形成了段页式存储管理方式。   段页式管理就是将...
  • Spark中内存模型管理

    千次阅读 2018-07-18 12:08:52
    Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色。理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优。本文旨在梳理出 Spark 内存管理的...
  • C/C++内存分配管理

    万次阅读 多人点赞 2018-08-13 14:57:23
    内存分配及管理 1.内存分配方式 在C++中内存分为5个区,分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 堆:堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言...
  • STM32内存管理

    千次阅读 2019-03-15 15:28:43
    内存管理实现方法有很多种,他们其实最终都是要实现 2 个函数: malloc 和 free; malloc 函数用于内存申请, free 函数用于内存释放。 介绍一种简单的实现方法,分块式内存管理: 原理: malloc分析 首先确定.....
  • 内存管理的功能 内存空间的分配与回收:由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储分配的麻烦,提高编程效率。 地址转换:在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致,因此...
  • MMU内存管理单元详解

    千次阅读 2020-04-28 23:15:07
    在传统的批处理系统如 DOS 系统,应用程序与操作系统在内存中的布局大致如下图: 应用程序直接访问物理内存,操作系统占用一部分内存区。 操作系统的职责是“加载”应用程序,“运行”或“卸载”应用程序。...
  • 操作系统实验四:内存管理

    千次阅读 2021-01-21 18:03:04
    (1)通过在Linux环境下对内存管理的基本操作了解Linux如何对内存及虚拟内存进行管理; (2)掌握可变分区管理内存的方法。 二、实验内容 (1)验证实验: ① Linux 命令FREE显示内存状态情况,观察结果并分析; ② ...
  • JVM内存管理及GC机制

    万次阅读 2021-12-06 21:42:40
    Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。...
  • 共享内存实现原理

    万次阅读 2018-09-28 18:02:39
    共享内存的使用实现原理(必考必问,然后共享内存段被映射进进程空间之后,存在于进程空间的什么位置?共享内存段最大限制是多少?) nmap函数要求内核创建一个新额虚拟存储器区域,最好是从地质start开始的一个...
  • 内存管理:页式虚拟内存管理

    千次阅读 2019-12-17 21:00:38
    页式存储管理——虚拟内存——缺页中断,页面替换算法 开章明意: 创建一个进程(创建进程是在磁盘中),进程以字节为单位编号,然后再进程分为许多页(每页4KB),内存中有对应的页框(设定同页)。通过页表(记录...
  • 分块式内存管理原理

    千次阅读 2016-09-08 08:44:14
    内存管理实现方法有很多种,他们其实最终都是要实现 2 个函数:malloc 和 free;malloc 函数用于内存申请,free 函数用于内存释放。 分块式内存管理是众多内存管理方式中的一种。它的实现原理如下图所示。 ...
  • 操作系统实验——内存管理

    万次阅读 2017-11-10 18:56:25
    内存什么管理 在OS中,每个运行的进程都会占用内存,那么操作系统势必要做好两件事:内存分配和内存回收。这便是本次实验要做的模拟实验了。 内存分配策略 FF(首次适应算法) 这种策略旨在从最低地址的...
  • LiteOS-M动态内存管理

    千次阅读 2022-01-26 15:38:59
    LiteOS-M的动态内存管理将大块的预分配内存,通过最佳适应算法,动态分配给申请者。动态内存分配算法都无法避免内存碎片化,但通过最佳适应算法能够最大限度的减少内存碎片化。 代码实现文件: kernel/liteos_m/...
  • iOS内存管理——alloc/release/dealloc方法的GNUstep实现与Apple的实现接上篇关于iOS内存管理的规则考我们通过alloc/release/dealloc方法的具体实现来深入探讨内存管理什么是GNUstep `GNUstep`是`Cocoa`框架的...
  • Spark内核之内存管理

    千次阅读 2020-09-17 22:36:30
    2.1 早期内存管理(静态内存管理) 2.2 统一内存管理 2.3 同一管理内存的优点 三、存储内存管理 3.1 RDD的持久化机制 3.2RDD的缓存过程 3.3 淘汰与落盘 四、执行内存管理 4.1 Shuffle Write 4.2 Shuffle ...
  • 包括:内存管理单元MMU的作用,虚拟内存与物理内存之间的映射方式,页表的概念,高速缓存(Cache)的作用,物理内存与高速缓存之间的映射关系等。当然,想要深入了解,本文并不适合,本文只是从原理上,讲述以上几者...
  • Linux内存描述之高端内存--Linux内存管理(五)

    万次阅读 多人点赞 2016-08-31 14:33:52
    日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 Linux-4.7 X86 & arm ... Linux内存管理 http://blog.csdn.net/vanbreaker/article/details/75799411 前景回顾前面我们讲到服务器体系(SMP, NUMA, M

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,167,622
精华内容 467,048
热门标签
关键字:

内存管理通过什么实现