精华内容
下载资源
问答
  • 内存管理算法实现

    千次阅读 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.

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

    展开全文
  • 两年前一位同事和我说过,单片机不能实现动态内存管理,两天后我在keil上利用malloc()在coterx m3芯片上实现了一个链表,然后把代码给他看了,对固执的人摆事实好过讲道理。之后我觉得使用malloc()并不能满足我的...

    两年前一位同事和我说过,单片机不能实现动态内存管理,两天后我在keil上利用malloc()在coterx m3芯片上实现了一个链表,然后把代码给他看了,对固执的人摆事实好过讲道理。

    之后我觉得使用malloc()并不能满足我的需求,然后想自己实现一个heap管理。

    这就是这篇文章的由来,这是我今天下午突然想到的一种简单的方法,其实这很没有意义,因为我能想到的东西,别人都已经做出来了。嗯,姑且当是一个编程题的实现吧。

    数据结构很简单,就是先开辟一个大数组,然后将数组分割,每个块大小固定,我定义为16个字节,每个块用一个字节管理,然后记录下有几个块没有被使用。

    malloc的实现,输入形参和malloc一样,就是内存需求大小,申请成功返回地址,不成功返回NULL。实现思想如下,先计算的出需要几个内存块,然后检测剩余内存块是否足够,如果足够,再检测是否连续,都满足的话,将第一个内存块的管理单元赋值1,第二个赋值2,以此类推。然后将剩余内存块数量减去使用掉的数量,返回地址。

    free的实现,输入形参和free一样,就是malloc获得的地址,无返回。实现思想如下,先计算出地址相对heap起始地址的偏移,然后得出相应的内存管理单元,如果该内存管理单元为1,将该单元以下连续管理单元都清空,然后将剩余内存块加上相应的地址,返回。

    这份代码算是1.0版本,没有dubug过,不建议使用。没有debug的原因是没有想到怎么实现碎片管理的办法,我想在2.0版本上面实现,这个姑且算是一份伪代码吧。如果谁有内存碎片管理算法的一些想法的话,欢迎讨论。

    #include "string.h"
    #define HEAP_QLY 16
    
    struct general_buf
    {
    	uint32_t block_qly;			//剩余缓存块
    	uint8_t dirty[100];			//缓存空间脏标志	
    	uint8_t buffer[HEAP_QLY*100];		//缓存空间
    }Heap_Buf;
    
    /*
     *	功能:通用缓存初始化
     *  输入:无
     *  输入:无
     *  返回:无
     *  备注:
    */
    void heap_buffer_init(void)
    {
    	Heap_Buf.block_qly = sizeof(Heap_Buf.dirty);
    	memset(Heap_Buf.buffer,0,sizeof(Heap_Buf.buffer));
    	memset(Heap_Buf.dirty,0,sizeof(Heap_Buf.dirty));
    }
    
    /*
     *	功能:堆内存获取函数
     *  输入:无
     *  输入:无
     *  返回:无
     *  备注:
    */
    void* my_malloc(uint32_t size)
    {
    	uint32_t size_need=size/HEAP_QLY+(size%16?1:0);/*获得块需求*/
    	uint32_t i,j;
    	uint32_t free_num=0;
    	uint8_t* address=NULL;
    	uint8_t enought_space=0;
    	
    	if(size_need>Heap_Buf.block_qly)
    		return NULL;
    	
    	for(i=0;i<Heap_Buf.block_qly;i++){
    		if(!Heap_Buf.dirty[i]){
    			free_num++;
    			if(free_num>=size_need){
    				enought_space=1;
    				break;
    			}
    		}else
    			free_num=0;
    	}
    	
    	if(enought_space){
    		Heap_Buf.block_qly -= free_num;
    		address = &Heap_Buf.buffer[(i-(free_num-1))*HEAP_QLY];
    		for(j=0;j<free_num;j++)
    			Heap_Buf.dirty[(i-(free_num-1))+j] = j;
    	}
    	
    	return address;
    }
    
    /*
     *	功能:堆内存释放函数
     *  输入:无
     *  输入:无
     *  返回:无
     *  备注:
    */
    void my_free(void* address)
    {
    	uint32_t offset=((uint8_t*)address-Heap_Buf.buffer)/HEAP_QLY;
    	uint32_t i=0;
    	
    	if(Heap_Buf.dirty[offset] != 1){
    		return;
    	}else{
    		 
    		do{
    			offset += i;
    			i = Heap_Buf.dirty[offset];
    			Heap_Buf.dirty[offset] = 0;
    			Heap_Buf.block_qly++;
    		}while(1!=i||0!=i||offset>=sizeof(Heap_Buf.dirty));
    	}
    }
    
    
    
    
    

    写于2018年3月20日夜

    深圳

    展开全文
  • iOS内存管理——alloc/release/dealloc方法的GNUstep实现与Apple的实现接上篇关于iOS内存管理的规则考我们通过alloc/release/dealloc方法的具体实现来深入探讨内存管理什么是GNUstep `GNUstep`是`Cocoa`框架的...

    关于阅读《Object-C高级编程-iOS与OS X多线程和内存管理》一书后的iOS内存管理系列思考

    iOS内存管理——alloc/release/dealloc方法的GNUstep实现与Apple的实现

    接上篇关于iOS内存管理的规则考我们通过alloc/release/dealloc方法的具体实现来深入探讨内存管理。

    什么是GNUstep

        `GNUstep`是`Cocoa`框架的互换框架,从源代码的实现上来说,虽然和Apple不是完全一样,但是从开发者的角度来看,两者的行为和实现方式是一样,或者说是非常相似。
        因为`NSObject`类的`Foundation`框架是不开源的,不过,`Foundation`框架使用的`Core Foundation`框架的源码和通过调用`NSObject`类进行内存管理部分的源码是公开的。
        所以,我们先来了解`GNUstep`的实现方式,有助于我们去理解`Apple`的实现方式。
    

    GNUstep更多详细内容请查看官网

    搞出些事情

    • GNUstep/modules/core/base/Source/NSObject.m alloc
    + (id)alloc {
        return [self allocWithZone:NSDefaultMallocZone()];
    }
    
    + (id)allocWithZone:(struct _NSZone *)zone {
        return NSAllocateObject(self, 0, zone);
    }

    我们可以看到内存的分配最重是通过allocWithZoneNSAllocateObject方法分配的。

    我们来看一下NSAllocateObject的声明:

    NSAllocateObject(<#Class  _Nonnull aClass#>, <#NSUInteger extraBytes#>, <#NSZone * _Nullable zone#>)

    实现:

    static obj_layout {
        NSUInteger retained;
    };
    
    inline id
    
    NSAllocateObject(Class  _Nonnull aClass, NSUInteger extraBytes, NSZone * _Nullable zone){
        int size = 计算容纳对象所需内存大小;
        id new = NSZoneMalloc(zone, size);
        memset(new, 0, zize);
        new = (id)&((static obj_layout *) new)[1];
             
    }
    

    通过上述代码可以看出,NSAllocateObject方法通过调用NSZoneMalloc方法来分配存放对象所需的内存空间,之后将该空间置0,最后返回作为对象而使用的指针。

    区域
    NSZone是什么?
    NSZone是Apple为了防止内存碎片化而引入结构。对内存分配的区域本身进行多重化管理,根据使用对象的目的,对象的大小分配内存,从而提高内存的管理效率。
    但是,现在iOS的运行时系统知识简单的忽略了区域的概念。运行时系统中的内存管理本身已经极具效率,使用区域来管理区域反而会引起效率低下以及源码复杂化的问题。
    多区域内存管理

    去掉NSZone后的alloc源码

    • GNUstep/modules/core/base/Source/NSObject.m alloc去NSZone版
    + (id)alloc {
        int size = sizeof(struct objc_layout) + 对象大小;
        struct objc_layout *p = (struct objc_layout *)calloc(1, size);
        return (id)(p+1);
    }

    objc_layout中的retained是用来记录引用计数

    此结构体在每一块对象内存的头部,盖对象内存块全部置0后返回,如图:
    alloc返回内存图

    我们可以使用retainCount实例方法获取当前的引用计数。

    NSObject *obj1 = [[NSObject alloc] init];
    
    NSLog(@"obj1 retain count = %lu", (unsigned long)[_obj1 retainCount]);

    打印结果:
    2016-12-21 16:04:07.579 acm[66972:880151] obj1 retain count = 1

    - (NSInteger)retainCount {
        return NSExtraRefCount(self) + 1;
    }
    
    inline NSUInteger
    NSExtraRefCount(id  _Nonnull object) {
        return ((struct obj_layout *)object)[-1].retained;
    }

    这段代码中 ((struct obj_layout *)object)[-1]可能对C语言不熟悉的同学不太理解,我来解释一下。

    首先[-1]的意思是指针向上移动一个对象的大小。
    前边我们的讲述中,在对象内存的上方会有一个小的内存块用来存储引用计数的结构体struct obj_layout
    (struct obj_layout *)来修饰object是为了当我们移动指针的时候移动的大小是 一个struct obj_layout的大小,而不是一个object的大小.


    前边我们也说到,每次内存分配后都会把对象的内存区域置0,这是为什么?
    这个问题我也有些蒙蔽,暂且搁置。希望有同学给予解答。

    因为为了满足内存管理的规则,在分配时全部置0,所以retained0.
    在调用retainCount的时候会return NSExtraRefCount(self)+ 1,我们可以推测出,retain方法使retained变量+1,而release方法是retained变量减1.

    • GNUstep/modules/core/base/Source/NSObject.m retain
    - (id)retain {
        NSIncrementExtraRefCount(self);
        return self;
    }
    
    inline void
    NSIncrementExtraRefCount(id  _Nonnull object)  {
    <!--retained最大值判断-->
        if (((struct obj_layout *)object)[-1].retained == UINT_MAX - 1) {
            [NSException raise:NSInternalInconsistencyException format:@"NSIncrementExtraRefCount() asked to increment too far"];
        }
    <!--没有超过最大值则加1-->          
        ((static obj_layout *)object)[-1].retained++;
    
    }
    • GNUstep/modules/core/base/Source/NSObject.m release
    - (void)release {
        if (NSDecrementExtraRefCountWasZero(self)) {
            [self dealloc];
        }
    }
    
    BOOL
    NSDecrementExtraRefCountWasZero(id  _Nonnull object) {
        if (((struct obj_layout *)object)[-1].retained == 0) {
            return YES;
        } else {
            return NO;
        }
    }

    相信大家对上边的两个方法的规则已经有一个了结,在调用retainrelease都会判断极值,分别在条件允许时调用抛异常或dealloc

    我们再来看看dealloc时如何实现的

    • GNUstep/modules/core/base/Source/NSObject.m dealloc
    - (void)dealloc {
        NSDeallocateObject(self);
    }
    
    inline void
    NSDeallocateObject(id  _Nonnull object) {
    
        struct obj_layout *o = &((struct obj_layout *)object)[-1];
    
        free(o);
    }
    

    不难发现,dealloc方法获取到从存放 obj_layout 结构的内存头部开始的指针后释放它所指向的内存块。

    GNUstep中alloc/retain/release/dealloc中的实现总结

    • Objective-C的对象中存有引用计数这个变量.
    • 调用alloc或者retain后,引用计数+1.
    • 调用release后,引用计数-1.
    • 引用计数为0时,调用dealloc废弃对象.

    连猜带想,看苹果如何实现的alloc/retain/release/dealloc

    我们看完了GNUstep中的各个方法实现方式,再来猜想推测一下苹果的实现,如今NSObject类的源码没有公开,我们利用lldb(Xcode调试器)和iOS的历史来追溯其实现方式。

    在NSObject类的alloc类方法上设置断点,追踪函数调用

    //NSObject alloc调用顺序
    +alloc
    +allocWithZone:
    class_createInstance
    calloc

    可以看出这个调用顺序和GNUstep的调用顺序非常的相似

    //GNUstep alloc调用顺序
    +alloc
    +allocWithZone:
    NSAllocateObject
    NSZoneMalloc

    通过 objc4库中的 reuntime/objc-runtime-new.mm文件进行确认。

    官方文档中的class_createInstance
    class_createInstance

    我们在来看看retainCount/retain/release的实现方式(调用栈)。

    • retainCount
    -retainCount
    __CFDoExternRefOperation
    CFBasicHashGetCountOfKey
    • retain
    -retain
    __CFDoExternRefOperation
    CFBasicHashAddValue
    • release
    -release
    __CFDoExternRefOperation
    CFBasicHashRemoveValue

    这个时候们必需去看看__CFDoExternRefOperation做了什么

    • CF/CFRuntime.c __CFDoExternRefOperation
    int __CFDoExternRefOperation(uintptr_t op,id obj) {
        CFBasicHashRef table = 取得对象对应的散列表(obj);
        int countswitch(op) {
            //retainCount
            case OPERATION_retainCount:
                count = CFBasicHashGetCountOfKey(table, obj);
                return count;
    
            //retain
            case OPERATION_retaion:
                CFBasicHashAddValue(table, obj);
                return obj;
    
            //release
            case OPERATION_release:
                count = CFBasicHashRemoveValue(table, obj);
                return 0==count;
        }
    }

    看到这里我们也就可以大致推测三个方法的实现方式了:

    - (NSUInteger)retainCount {
        return (NSUInteger)__CFDoExternRefOperation(OPERATION_retainCount, self);
    }
    
    - (id)retain {
        return (id)__CFDoExternRefOperation(OPERATION_retain, self);
    
    }
    
    - (void)release {
        return __CFDoExternRefOperation(OPERATION_release, self);
    }

    推测苹果实现alloc/retain/release/retainCount方法的总结

    我们可以从__CFDoExternRefOperation函数和由次函数调用的各个函数名看出,苹果采用了散列表(引用计数表)来管理引用计数。

    如图:

    不难看出,GNUstep将引用计数保存在对象占用内存块头部的变量中,而苹果的实现,则是保存在用用计数表的记录中,GNUstep的实现在我们看来是没有任何问题的,但是苹果这么实现也有它的道理。

    使用内存块头部管理引用计数好处:

    • 少量代码即可实现
    • 能够在同一张表中统一的管理引用计数用内存块和对象用内存块。

    使用引用计数表来管理引用计数的好处:

    • 对象用内存块的分配无需考虑头部内存块的存在。
    • 引用计数表各记录中存有内存块地址,可以从各个记录追溯到对象的内存块。即使出现故障导致对象占用的内存块损坏,但只要引用计数表没有损坏,就能确认各个内存块的位置。
    • 有助于利用工具检测各个对象的持有者是否存在,即检测内存泄漏的原理。

    参考资料

    《Object-C高级编程——iOS与OS X多线程和内存管理》--[日]Kazuki Sakamoto Tomohiko Furumoto著

    展开全文
  • C语言实现简单的内存管理机制

    千次阅读 2018-03-15 22:04:22
    在C类型程序中,栈内存比较珍贵,大部分用在局部或者类成员(因为稀少… 不适合长时间占用一块栈内存),对于大量...针对这种情况,我以自己的习惯写了一个简单的内存管理结构,加深自己对内存的理解。 首先简单说...

      在C类型程序中,栈内存比较珍贵,大部分用在局部或者类成员(因为稀少… 不适合长时间占用一块栈内存),对于大量数据一般使用堆来分配。重复用堆分配有一个显著的缺点就是容易造成外部碎片,在这种情况下系统内存不再连贯,一些内存得不到使用,久而久之系统内存会变的越来越少,长时间处理大数据会出现一些不可预料的问题。

      针对这种情况,我以自己的习惯写了一个简单的内存管理结构,加深自己对内存的理解。

      首先简单说下我实验的结构形式:
        1.默认分配一块大的内存区域(类似内存池,默认大小是100M,构造的时候可以自己指定区域的大小),后期根据需要的内存动态增加新的内存区域(默认大小也是100M,如果需要使用的内存超过100M将会分配需要使用的内存加上最小范围值),以链表的形式进行链接;

        2.使用链表结构标记已使用和已归还的内存范围;

        3.每次获取内存时先从已归还的内存结构中进行匹配,如果没有匹配到合适的内存大小,将从内存区域中划分出一块新的内存使用;

        4.增加每段内存的保护字节:1.最小范围值 默认为1个字节,2.最大范围值 默认为2个字节。每次获取内存时首先根据 ( 大于等于需要的内存加最小范围值 或 <= 需要的内存加最大范围值 )进行匹配已归还的内存结构;

        5.内存区域以及内存链表结构都是使用计数表示在相同类型中的指定位置;

        6.清除指定内存区域(内存池)时,把标记使用这块内存的链表内存置为空,等待下次分配使用;

        7.链表内存结构只会在对象析构的时候进行释放,保证了内存分配速度越来越快并且稳定的情况(不在对象使用的时候进行删除链表内存节点,保证了内存分配的效率);

        8.对象析构的时候会释放掉所有的内存区域(内存池)以及链表内存结构,保证了结构的稳定性。

      下面贴上.h文件

    #include <stdio.h>
    //默认单个内存池大小
    #define MEMPOOLSIZE 100 * 1024 * 1024
    
    //内存管理表
    //允许使用者追加分配内存,追加的内存将会保存在下一个结构中
    typedef struct MemoryStore
    {
    	int Count;
    	//总容量
    	unsigned long long MemVolumeDose;
    	//起始地址
    	unsigned long long StartAddress;
    	//末尾地址
    	unsigned long long EndAddress;
    	//当前使用量
    	unsigned long long CurrentUsageAmount;
    	//剩余容量
    	unsigned long SurplusVolumeDose;
    	MemoryStore *Priv, *Next;
    
    	void Init()
    	{
    		Count = MemVolumeDose = StartAddress = EndAddress = CurrentUsageAmount = SurplusVolumeDose = 0;
    		Priv = Next = 0;
    	}
    }* PMemoryStore;
    
    
    //链表内存管理结构
    typedef struct MemList
    {
    	//记录是第多少个节点
    	int Count;
    	//记录内存属于哪个池子
    	int nPoolCount;
    	//起始地址
    	unsigned long StartAddress;
    	//末尾地址
    	unsigned long EndAddress;
    	//当前使用量
    	unsigned long CurrentUsgeAmount;
    	//标记是否已经保存了数据
    	bool bValid;
    	MemList *Priv, *Next;
    
    	void Init()
    	{
    		Count = nPoolCount = StartAddress = EndAddress = CurrentUsgeAmount = 0;
    		bValid = 0;
    		Priv = Next = 0;
    	}
    }* PMemList;
    
    
    
    //代码实现结构
    struct MemoryPool_
    {
    	MemoryPool_(unsigned long long AllocSize = MEMPOOLSIZE);
    	virtual ~MemoryPool_();
    
    	//内存分配
    	void *MemAlloc(int nSize);
    	//内存释放
    	bool MemFree(void * ptr);
    	//释放内存池 类对象销毁前进行自动释放
    	bool MemPoolFree();
    	//获取最后一次出现的错误
    	char *GetLastError();
    	//匹配的内存比需要分配的内存多的字节数(最小值 比如默认匹配到的内存比需要分配的内存多一个字节)
    	bool SetComPareMemMini(int nMini);
    	//匹配的内存比需要分配的内存多的字节数(最大值 比如默认匹配到的内存比需要分配的内存多五个字节)
    	bool SetComPareMemMax(int nMax);
    	
    private://内部使用
    	//内存池管理
    	PMemoryStore m_Memory,m_MemoryEnd;
    	//数据管理
    	PMemList m_MemHead,m_MemCurrent,m_MemEnd;
    	char m_LastError[256];
    	//匹配最小值差距
    	int m_nCompareMini;
    	//匹配最大值差距
    	int m_nCompareMax;
    	//初始化内存池大小
    	unsigned long long m_nInitPoolSize;
    	//标记被解除占用的一节
    	int m_nCount;
    private:
    	//执行中最后出现的错误进行保存
    	bool WriteLastError(const char *data);
    	//初始化内存池
    	bool InitMemPool(int AllocSize);
    	//创建下一个内存池
    	bool CreateNextMemPool(int AllocSize);
    	//分配一节内存管理链表信息
    	PMemList GetMemList();
    	//初始化内存管理链表头信息
    	bool InitMemHead();
    	//获取内存管理管理头信息
    	PMemList GetMemListHead();
    	//从内存池中分配一块内存
    	void *GetPoolMem(int nSize);
    	//获取首个内存池信息
    	PMemoryStore GetPoolHead();
    	//获取最后一个内存池信息
    	PMemoryStore GetPoolEnd();
    	//从一块内存池中获取数据
    	void *GetAPoolofMem(PMemoryStore obj,int nSize);
    	//获取最后一个节点
    	PMemList GetEndList();
    	//创建第一个节点以及分配内存
    	void *CreateFirstMem(int nSize,bool bValid);
    	//创建新的节点以及分配内存 bValid为true标记为已使用内存 ,false标记为未使用
    	void *CreateNextMem(PMemoryStore obj,int nSize,bool bValid);
    	//创建第一个节点
    	void *CreateListHead(int nSize);
    	//获取节点头
    	PMemList GetHeadList();
    	//释放指定编号内存池
    	bool MemPoolFree_(int nCount);
    	//修改指定内存块当前使用量
    	bool RevampMemUsgeAmount(int nCount,long long nSize);
    	//解除占用标记的某块内存 ,释放类对象前统一释放
    	bool MemListFree_(int nPoolCount);
    	//标记第一个解除占用的内存
    	bool SetAllocList(int Count);
    	//获取第一个被解除占用的内存节点
    	int GetAllocList();
    	//使用被解除占用的节点分配内存
    	void *AllocMemList(int nCount,int nSize,bool bValid);
    	//根据计数获取list节点
    	PMemList GetCountList(int Count);
    	//获取可以分出内存的池子,这个直接从空闲内存中取出需要的内存
    	PMemoryStore GetValidMemPool(int nSize);
    	//释放指定节点,返回下一个节点
    	PMemList FreeList_(int Count);
    	//释放链表的所有节点
    	bool FreeList();
    };
    

      下面贴上.cpp文件

    #include "stdafx.h"
    #include "TestMemoryPool.h"
    
    MemoryPool_::MemoryPool_(unsigned long long AllocSize):m_Memory(0),m_MemHead(0)
    	,m_MemCurrent(0),m_MemEnd(0),m_nInitPoolSize(AllocSize)
    {
    	m_nCompareMini = 1;
    	m_nCompareMax = 5;
    	memset(m_LastError,0,sizeof(m_LastError));
    }
    
    MemoryPool_::~MemoryPool_()
    {
    	MemPoolFree();
    	FreeList();
    }
    
    bool MemoryPool_::SetComPareMemMini(int nMini)
    {
    	if (1 >= nMini)
    	{
    		return false;
    	}
    	m_nCompareMini = nMini;
    	return true;
    }
    
    bool MemoryPool_::SetComPareMemMax(int nMax)
    {
    	if (1 >= nMax)
    	{
    		return false;
    	}
    	m_nCompareMax = nMax;
    	return true;
    }
    
    //获取执行中出现的最后一条错误
    char *MemoryPool_::GetLastError()
    {
    	return m_LastError;
    }
    
    //写入错误信息
    bool MemoryPool_::WriteLastError(const char *data)
    {
    	if (0 == data)
    		return false;
    	memset(m_LastError,0,sizeof(m_LastError));
    	memcpy(m_LastError,data,sizeof(data));
    	return true;
    }
    //初始化内存池
    bool MemoryPool_::InitMemPool(int AllocSize)
    {
    	if (0 == m_Memory)
    	{
    		m_Memory = (PMemoryStore)malloc(sizeof(MemoryStore));
    		m_Memory->Init();
    	}
    	if (0 == m_Memory)
    		return false;
    	//构建池子
    	if (0 < AllocSize)
    	{
    		m_Memory->MemVolumeDose = AllocSize;
    		char *Mem = (char *)malloc(AllocSize);
    		m_Memory->StartAddress = (unsigned long long)Mem;
    		m_Memory->EndAddress = (m_Memory->StartAddress + AllocSize);
    	}
    	else
    	{
    		m_Memory->MemVolumeDose = MEMPOOLSIZE;
    		char *Mem = (char *)malloc(MEMPOOLSIZE);
    		m_Memory->StartAddress = (unsigned long long)Mem;
    		m_Memory->EndAddress = (m_Memory->StartAddress + MEMPOOLSIZE);
    	}
    	m_Memory->Count = 1;
    	m_Memory->CurrentUsageAmount = 0;
    	m_Memory->SurplusVolumeDose = m_Memory->MemVolumeDose;
    
    	//分配内存失败
    	if (0 ==  m_Memory->StartAddress)
    	{
    		WriteLastError("this MemoryAlloc is Not Valid");
    		return false;
    	}
    	m_MemoryEnd = m_Memory;
    	return true; 
    }
    
    //创建下一个内存池
    bool MemoryPool_::CreateNextMemPool(int AllocSize)
    {
    	PMemoryStore memoryPool = GetPoolHead();
    	if (0 == memoryPool)
    	{
    		InitMemPool(((AllocSize + m_nCompareMini >= MEMPOOLSIZE) ? (AllocSize + m_nCompareMini) : MEMPOOLSIZE));
    		return true;
    	}
    	while (memoryPool && 0 != memoryPool->Next)
    		memoryPool = memoryPool->Next;
    	memoryPool->Next = (PMemoryStore)malloc(sizeof(MemoryStore));
    	memoryPool->Next->Init();
    	//构建池子
    	if (0 < AllocSize)
    	{
    		memoryPool->Next->MemVolumeDose = AllocSize;
    		char *Mem = (char *)malloc(AllocSize);
    		memoryPool->Next->StartAddress = (unsigned long long)Mem;
    		memoryPool->Next->EndAddress = (memoryPool->Next->StartAddress + AllocSize);
    	}
    	else
    	{
    		memoryPool->Next->MemVolumeDose = MEMPOOLSIZE;
    		char *Mem = (char *)malloc(MEMPOOLSIZE);
    		memoryPool->Next->StartAddress = (unsigned long long)Mem;
    		memoryPool->Next->EndAddress = (memoryPool->Next->StartAddress + MEMPOOLSIZE);
    	}
    	memoryPool->Next->Count = (memoryPool->Count + 1);
    	memoryPool->Next->CurrentUsageAmount = 0;
    	memoryPool->Next->SurplusVolumeDose = memoryPool->Next->MemVolumeDose;
    
    	//分配内存失败
    	if (0 ==  memoryPool->Next->StartAddress)
    	{
    		WriteLastError("this MemoryAlloc is Not Valid");
    		return false;
    	}
    	m_MemoryEnd = memoryPool->Next;
    	m_MemoryEnd->Priv = memoryPool;
    	return true; 
    }
    
    //内存分配
    void *MemoryPool_::MemAlloc(int nSize)
    {
    	//增加头节点
    	if (0 == GetMemListHead())
    	{
    
    		if (!InitMemPool(m_nInitPoolSize))
    		{
    			WriteLastError("this Init is Not Valid");
    			return 0;
    		}
    		return CreateListHead(nSize);
    	}
    	else
    	{
    		return GetPoolMem(nSize);
    	}
    }
    //创建第一个节点
    void *MemoryPool_::CreateListHead(int nSize)
    {
     	return CreateFirstMem(nSize,1);
    }
    //获取节点头
    PMemList MemoryPool_::GetHeadList()
    {
    	return m_MemHead;
    }
    //获取首个内存池信息
    PMemoryStore MemoryPool_::GetPoolHead()
    {
    	return m_Memory;
    }
    //获取最后一个内存池信息
    PMemoryStore MemoryPool_::GetPoolEnd()
    {
    	return m_MemoryEnd;
    }
    //从所有内存池中取出未使用的内存地址
    void *MemoryPool_::GetPoolMem(int nSize)
    {
    	PMemoryStore pool = GetPoolHead();
    	
    	while (pool)
    	{
    		char *pData = (char *)GetAPoolofMem(pool,nSize);
    		if (0 != pData)
    			return (void *)pData;
    		pool = pool->Next;
    	}	
    	//如果所有的池子都遍历了还是没有合适内存,那么创建一个新的池子
    	if ((nSize + m_nCompareMini)  > MEMPOOLSIZE)
    		CreateNextMemPool(nSize + m_nCompareMini);
    	else
    		CreateNextMemPool(MEMPOOLSIZE);
    
    		char *pData = (char *)GetAPoolofMem(m_MemoryEnd,nSize);
    		return (void *)pData;
    }
    
    //从一块内存池中获取数据
    void *MemoryPool_::GetAPoolofMem(PMemoryStore obj,int nSize)
    {
    	if (0 >= obj->SurplusVolumeDose || nSize >= obj->SurplusVolumeDose)
    	{
    		return 0;
    	}
    		//如果达到查询的条件 开始遍历对应编号的内存池 ,为了最大利用内存选择从头开始遍历,如果没有数据插入到最后
    		PMemList listData = GetMemListHead();
    		while (listData && (0 != listData->Next))
    		{
    			//判断是否有解除占用的节点,如果有的话记录第一个,如果没有找到合适的内存链 ,那么用这个进行分配内存
    			if ((listData->nPoolCount == 0) && (0 < listData->Count))
    			{
    				SetAllocList(listData->Count);
    			}
    
    			//如果节点中保存的内存使用量大于或等于需要分配的内存,那么使用这块内存
    			if (((nSize + m_nCompareMini  <= listData->CurrentUsgeAmount) && (nSize + m_nCompareMax >= listData->CurrentUsgeAmount)) && (0 == listData->bValid))
    			{
    				RevampMemUsgeAmount(listData->nPoolCount,listData->CurrentUsgeAmount);
    				listData->bValid = 1;
    				return (void *)listData->StartAddress;
    			}
    			listData = listData->Next;
    		}
    		int nCount = GetAllocList();
    		if (0 < nCount)
    			return AllocMemList(nCount,nSize,1);
    	//创建新的节点保存分配内存
    	return CreateNextMem(obj,nSize,1);
    }
    
    //标记第一个被解除占用的内存节点
    bool MemoryPool_::SetAllocList(int Count)
    {
    	if (0 >= Count || 0 < m_nCount)
    		return false;
    	m_nCount = Count;
    	return true;
    }
    
    //获取第一个被解除占用的内存节点,当前保存的节点被使用后可以再次储存下一个被解除占用的内存节点
    int MemoryPool_::GetAllocList()
    {
    	int Count = m_nCount;
    	m_nCount = 0;
    	return Count;
    }
    
    //修改指定内存块当前使用量
    bool MemoryPool_::RevampMemUsgeAmount(int nCount,long long nSize)
    {
    	if (0 >= nCount)
    		return false;
    	PMemoryStore memPool = GetPoolHead();
    	while (memPool->Count != nCount)
    		memPool = memPool->Next;
    
    	if (0 != memPool)
    	{
    		memPool->CurrentUsageAmount += nSize;
    		memPool->SurplusVolumeDose = (memPool->MemVolumeDose - memPool->CurrentUsageAmount);
    	}
    	else
    		return false;
    
    	return true;
    }
    
    //创建第一个节点以及分配内存 ,如果不是第一个节点 走默认函数
    void *MemoryPool_::CreateFirstMem(int nSize,bool bValid)
    {
    	//如果头节点已经创建 调用默认内存分配
    	if (0 != m_MemHead)
    		return GetPoolMem(nSize);
    
    	PMemoryStore pool = GetPoolHead();
    
    	m_MemHead = GetMemList();
    	m_MemHead->Count = 1;
    	m_MemHead->StartAddress = (pool->StartAddress + pool->CurrentUsageAmount);
    	//多分配一个字节用来防止内存越界
    	m_MemHead->EndAddress = (m_MemHead->StartAddress + nSize + 1);
    	m_MemHead->CurrentUsgeAmount = (nSize + 1);
    	m_MemHead->nPoolCount = pool->Count;
    	m_MemHead->bValid = bValid;
    	pool->CurrentUsageAmount += (nSize + 1);
    	pool->SurplusVolumeDose -= pool->CurrentUsageAmount;
    	m_MemEnd = m_MemHead;
    	//分配出一段干净的内存 上层方便使用
    	memset((void *)m_MemHead->StartAddress,0,nSize + 1);
    	return (void *)m_MemHead->StartAddress;
    }
    
    //创建新的节点以及分配内存
    void *MemoryPool_::CreateNextMem(PMemoryStore obj,int nSize,bool bValid)
    {
    	PMemList list = GetEndList();
    	list->Next = GetMemList();
    	list->Next->Count = (list->Count + 1);
    	list->Next->StartAddress = (obj->StartAddress + obj->CurrentUsageAmount);
    	//多分配一个字节用来防止内存越界
    	list->Next->EndAddress = (list->Next->StartAddress + nSize + 1);
    	list->Next->CurrentUsgeAmount = (nSize + 1);
    	list->Next->nPoolCount = obj->Count;
    	list->Next->Priv = list;
    	list->Next->bValid = bValid;
    	obj->CurrentUsageAmount += (nSize + 1);
    	obj->SurplusVolumeDose -= obj->CurrentUsageAmount;
    	m_MemEnd = list->Next;
    	//分配出一段干净的内存 上层方便使用
    	memset((void *)list->Next->StartAddress,0,nSize + 1);
    	return (void *)list->Next->StartAddress;
    }
    
    //获取可以分出内存的池子,这个直接从空闲内存中取出需要的内存
    PMemoryStore MemoryPool_::GetValidMemPool(int nSize)
    {
    	PMemoryStore pool = GetPoolHead();
    	while (pool)
    	{
    		if (pool->SurplusVolumeDose >= (nSize + m_nCompareMini))
    		{
    			return pool;
    		}
    		pool = pool->Next;
    	}
    	//如果没有 就创建一个新的内存池
    	if (CreateNextMemPool(((nSize + m_nCompareMini) >= MEMPOOLSIZE ? (nSize + m_nCompareMini) : MEMPOOLSIZE)))
    		return GetPoolEnd();
    
    	return 0;
    }
    
    //使用被解除占用的节点分配内存
    void *MemoryPool_::AllocMemList(int nCount,int nSize,bool bValid)
    {
    	PMemList list = GetCountList(nCount);
    	if (0 == list)
    		return 0;
    	PMemoryStore memPool = GetValidMemPool(nSize);
    	if (0 == memPool)
    		return 0;
    
    	list->StartAddress = (memPool->StartAddress + memPool->CurrentUsageAmount);
    	//多分配一个字节用来防止内存越界
    	list->EndAddress = (list->StartAddress + nSize + 1);
    	list->CurrentUsgeAmount = (nSize + 1);
    	list->nPoolCount = memPool->Count;
    	list->bValid = bValid;
    	memPool->CurrentUsageAmount += (nSize + 1);
    	memPool->SurplusVolumeDose = (memPool->MemVolumeDose - memPool->CurrentUsageAmount);
    	//分配出一段干净的内存 方便使用
    	memset((void *)list->StartAddress,0,nSize + 1);
    	return (void *)list->StartAddress;
    }
    
    //根据计数获取list节点
    PMemList MemoryPool_::GetCountList(int Count)
    {
    	if (0 < Count)
    	{
    		PMemList list = GetHeadList();
    		while (list)
    		{
    			if (list->Count == Count)
    			{
    				return list;
    			}
    			list = list->Next;
    		}
    	}
    	return 0;
    }
    
    //获取最后一个节点
    PMemList MemoryPool_::GetEndList()
    {
    	return m_MemEnd;
    }
    
    //获取链表内存结构头节点
    PMemList MemoryPool_::GetMemListHead()
    {
    	return m_MemHead;
    }
    
    //创建链表内存结构头
    bool MemoryPool_::InitMemHead()
    {
    	m_MemHead = GetMemList();
    	m_MemCurrent = m_MemEnd = m_MemHead;
    	return (m_MemHead != 0 ? true : false);
    }
    
    //创建链接结构节点
    PMemList MemoryPool_::GetMemList()
    {
    	PMemList list = (PMemList)malloc(sizeof(MemList));
    	list->Init();
    	return list;
    }
    
    //内存释放
    bool MemoryPool_::MemFree(void * ptr)
    {
    	//根据分配的地址在内存池中匹配,匹配到后 修改结构数据后,等待再次使用
    	PMemList list = GetMemListHead();
    	while (list)
    	{
    		//如果链表中其中一节数据与需要释放的地址相同 ,而且这段数据属于使用中,属于这块内存
    		if ((list->StartAddress == (unsigned long)ptr) && (1 == list->bValid))
    		{
    			RevampMemUsgeAmount(list->nPoolCount,~(long long)list->CurrentUsgeAmount + 1);
    			//回收的时候不需要初始化内存,因为再次使用的时候会进行初始化
    			list->bValid = 0;
    			ptr = 0;
    			return true;
    		}
    		list = list->Next;
    	}
    	return false;
    }
    
    //释放内存池 ,这个不需要手动释放 ,类对象销毁前会进行释放
    bool MemoryPool_::MemPoolFree()
    {
    	PMemoryStore memPool = GetPoolHead();
    	while (0 != memPool)
    	{
    		PMemoryStore next =  memPool->Next;
    		MemPoolFree_(memPool->Count);
    		memPool = next;
    	}
    	return true;
    }
    
    //释放指定编号内存池
    bool MemoryPool_::MemPoolFree_(int nCount)
    {
    	PMemoryStore memPool = GetPoolHead();
    	while (memPool->Count != nCount)
    		memPool = memPool->Next;
    
    	if (0 == memPool)
    		return false;
    
    	PMemoryStore priv = 0,next = 0;
    	if (0 != memPool->Priv)
    		priv = memPool->Priv;
    	if (0 != memPool->Next)
    		next = memPool->Next;
    
    	MemListFree_(memPool->Count);
    	delete memPool;
    	memPool = 0;
    	if (0 != priv)
    		priv->Next = next;
    	else
    		m_Memory = next;
    	if (0 != next)
    		next->Priv = priv;
    	else
    		m_MemoryEnd = m_Memory;
    	return true;
    }
    
    //解除占用标记的某块内存 ,释放类对象前统一释放
    bool MemoryPool_::MemListFree_(int nPoolCount)
    {
    	PMemList list = GetHeadList();
    	while (list)
    	{
    		if (list->nPoolCount == nPoolCount)
    		{
    			list->nPoolCount = 0;
    			list->StartAddress = list->EndAddress = list->CurrentUsgeAmount = 0;
    			list->bValid = 0;
    		}
    		list = list->Next;
    	}
    	return true;
    }
    //释放指定节点,返回下一个节点
    PMemList MemoryPool_::FreeList_(int Count)
    {
    	PMemList list = GetCountList(Count);
    	if (0 == list)
    		return 0;
    
    	PMemList priv = 0,next = 0;
    	if (0 != list->Priv)
    		priv = list->Priv;
    	if (0 != list->Next)
    		next = list->Next;
    
    	delete list;
    	if (0 != priv)
    		priv->Next = next;
    	else
    		m_MemHead = next;
    	if (0 != next)
    		next->Priv = priv;
    	else
    		m_MemEnd = m_MemHead;
    	return next;
    }
    //释放链表的所有节点
    bool MemoryPool_::FreeList()
    {
    	PMemList list = GetHeadList();
    	while (list)
    	{
    		list = FreeList_(list->Count);
    	}
    	return true;
    }
    

      下面贴上测试代码

    	MemoryPool_ pool;
    	char *Test1 = (char *)pool.MemAlloc(100);
    	memcpy(Test1,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test1,0,sizeof(Test1));
    	char *Test2 = (char *)pool.MemAlloc(100);
    	memcpy(Test2,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test2,0,sizeof(Test2));
    	char *Test3 = (char *)pool.MemAlloc(100 * 1024 * 1024);
    	memcpy(Test3,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test3,0,sizeof(Test3));
    	char *Test4 = (char *)pool.MemAlloc(100 * 1024);
    	memcpy(Test4,"您好12312321312",sizeof("您好12312321312"));
    
    	pool.MemFree(Test1);
    	Test1 = 0;
    	pool.MemFree(Test2);
    	Test2 = 0;
    	pool.MemFree(Test3);
    	Test3 = 0;
    	pool.MemFree(Test4);
    	Test4 = 0;
    
    	Test1 = (char *)pool.MemAlloc(100);
    	memcpy(Test1,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test1,0,sizeof(Test1));
    	Test2 = (char *)pool.MemAlloc(100);
    	memcpy(Test2,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test2,0,sizeof(Test2));
    	Test3 = (char *)pool.MemAlloc(100 * 1024 * 1024);
    	memcpy(Test3,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test3,0,sizeof(Test3));
    	Test4 = (char *)pool.MemAlloc(100 * 1024);
    	memcpy(Test4,"您好12312321312",sizeof("您好12312321312"));
    
    	pool.MemPoolFree();
    
    	Test1 = (char *)pool.MemAlloc(100);
    	memcpy(Test1,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test1,0,sizeof(Test1));
    	Test2 = (char *)pool.MemAlloc(100);
    	memcpy(Test2,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test2,0,sizeof(Test2));
    	Test3 = (char *)pool.MemAlloc(100 * 1024 * 1024);
    	memcpy(Test3,"您好12312321312",sizeof("您好12312321312"));
    	memset(Test3,0,sizeof(Test3));
    	Test4 = (char *)pool.MemAlloc(100 * 1024);
    	memcpy(Test4,"您好12312321312",sizeof("您好12312321312"));
    

      文件下载地址:https://download.csdn.net/download/a29562268/10289385!

    展开全文
  • 内存管理

    万次阅读 2015-03-12 17:09:40
    内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存泄漏几乎在每个C++...
  • 文章目录Netty如何实现高性能内存管理ByteBuf分类池化(Pooled)对象管理1 算法设计1.1 整体原理1.2 算法结构1.3 申请/释放内存1.4 巨型对象内存管理1.5 小对象内存管理2 弹性伸缩2.1 PoolChunk管理2.2 PoolSubpage...
  • Android内存管理机制详解

    万次阅读 多人点赞 2012-12-13 10:37:33
    这是Linux内存管理的一个优秀特性,在这方面,区别于 Windows的内存管理。主要特点是,无论物理内存有多大,Linux都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的...
  • 内存管理我的理解是分为两个部分,一个是物理内存的管理,另一个部分是物理内存地址到虚拟地址的转换。 物理内存管理 内核中实现了很多机制和算法来进行物理内存的管理,比如大名鼎鼎的伙伴系统,以及slab分配器等等...
  • Java内存管理

    万次阅读 多人点赞 2016-03-08 21:36:06
    不过看了一遍《深入Java虚拟机》再来理解Java内存管理会好很多。接下来一起学习下Java内存管理吧。请注意上图的这个:我们再来复习下进程与线程吧:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,...
  • 一、内存管理概述 (一)、虚拟内存实现结构 (1)内存映射模块(mmap):负责把磁盘文件的逻辑地址映射到虚拟地址,以及把虚拟地址映射到物理地址。 (2)交换模块(swap):负责控制内存内容的换入和换出,...
  • Flink 原理与实现内存管理

    千次阅读 2018-09-07 11:35:13
    原文地址:https://yq.aliyun.com/articles/57815?spm=a2c4e.11153940.blogrightarea64820.29.71e5167cM5y5cc ...基于 JVM 的数据分析引擎都需要面对将大量数据存到内存中,这就不得不面对 JVM 存...
  • Android 内存管理机制

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

    千次阅读 2019-03-15 15:28:43
    内存管理实现方法有很多种,他们其实最终都是要实现 2 个函数: malloc 和 free; malloc 函数用于内存申请, free 函数用于内存释放。 介绍一种简单的实现方法,分块式内存管理: 原理: malloc分析 首先确定.....
  • 前面两个是用户态在堆上分配一段连续(虚拟地址)的内存空间,然后可以通过free释放,但是,同时也会有很多人对其背后的实现机制不了解。 这篇文章则是通过介绍这三个函数,并简单的予以实现,对比现有C的标准库...
  • Linux内存管理

    万次阅读 2015-11-08 15:24:57
    Linux内存管理 前言 对于内存部分需要知道: 地址映射内存管理的方式缺页异常 ...在进程看来,内存分为内核态和...从用户态到内核态一般通过系统调用、中断来实现。用户态的内存被划分为不同的区域用于不同的目的:
  • 3.1.2 操作系统内存管理管些什么

    千次阅读 多人点赞 2020-04-21 20:57:51
    内存空间的扩展(实现虚拟性)3.地址转换三种方式4.内存保护两种方式 0.思维导图 1.内存空间的分配与回收 2.内存空间的扩展(实现虚拟性) 3.地址转换 三种方式 4.内存保护 两种方式 ...
  • 内存与操作系统内存管理

    千次阅读 2021-02-28 15:10:12
    内存与操作系统内存管理 文章目录内存与操作系统内存管理一、内存的基础知识二、内存管理2.1 内存空间扩充2.2 内存空间的分配与回收 一、内存的基础知识   内存是用于存放数据的硬件,程序执行前需要将数据放入...
  • Java应用程序是运行在JVM上的,得益于JVM的内存管理和垃圾收集机制,开发人员的效率得到了显著提升,也不容易出现内存溢出和泄漏问题。但正是因为开发人员把内存的控制权交给了JVM,一旦出现内存方面的问题,如果不...
  • OC内存管理

    万次阅读 2014-10-07 00:44:55
    (一)为什么要进行内存管理。 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再...
  • C++ 内存池介绍与经典内存池的实现

    万次阅读 多人点赞 2015-11-01 00:04:38
    1.默认内存管理函数的不足利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的开销。系统在接收到分配一定大小内存的请求时,首先查找内部维护的内存空闲块表,并且需要根据一定的...
  • 动态内存管理

    千次阅读 2009-02-19 09:17:00
    有两种方法实现动态内存管理。一是显示内存管理EMM(Explicit Memory Management)。在EMM方式,内存从Heap中进行分配,用完后手动回收。程序使用malloc()函数分配整数数组,并使用free()函数释放分配的内存。二是...
  • 18.简易内存管理

    千次阅读 2018-11-20 19:41:49
    上一节实现了对内存信息的解析,操作系统的一个重要功能就是提供内存管理,为应用程序提供动态内存分配。一个好的内存管理算法不会使系统内存资源耗尽、内存碎片较少。 目标 实现简易的内存分配、回收管理算法。 ...
  • 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 ...
  • spark 内存管理

    千次阅读 2016-05-17 15:16:08
    从Spark 1.6版本开始,Spark采用Unified Memory Management这样一种新的内存管理模型。 Spark中的内存使用分为两部分:执行(execution)与存储(storage)。执行内存主要用于shuffles、joins、sorts和aggregations...
  • 日期 内核版本 架构 作者 GitHub ... Linux内存管理内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到
  • 内核内存池管理技术实现分析一.Linux系统内核内存管理简介Linux采用“按需调页”算法,支持三层页式存储管理策略。将每个用户进程4GB长度的虚拟内存划分成固定大小的页面。其中0至3GB是用户态空间,由各进程独占;3...
  • 日期 内核版本 架构 作者 GitHub CSDN 2016-09-01 ...在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,036,181
精华内容 414,472
关键字:

内存管理通过什么实现