内存使用技巧及内存池实现(二)

         本文所有内容包括源码均是作者原创,出于尊重,如果转载请表明出处 ^_^        

        上一章节,提到了内存池的使用。其实内存池的作用看名字也能猜到,"池"意味着资源是同一管理和创建释放的,就像数据库的连接池、系统的线程池。主要就是为了避免创建、销毁资源的代价。c标准的malloc/free会造成大量的内存碎片以至于影响效率,所以“内存池”的技术某种程度上避免了这种消耗和影响。

        本人觉得实现的内存池可以分为3级:

           1、初级的简单内存池实现:解决malloc小空间的碎片化,托管回收。适用于函数或类,不跨线程 

           2、高级的内存池:通过块链式的方式长期托管内存,可以半自动的释放内存,并可以动态规划内存的块存储(类似linux内核BuddySystem)。

           3、可以托管内存和相关资源(文件句柄、数据库连接)的池 : 将和该块内存相关联的内存、资源整合,统一托管!全局托管资源。

        本文会实现并讲解1、2中的内存池实现方式。第3种时间和技术有限,大家可以自行写一写,或者用C++的RAII技术和STL中的实现来用。


        简单的内存池实现,核心思想就是想申请一块大内存(mb级别,并且为512KB的整数倍,好处是和linux内存管理配套,数字根据应用不同可以改),这样做可能有一定的浪费,不过试想一下,如果只是申请几十个Byte,根本用不到内存池。用到了内存池肯定空间不会太小。然后从这块大内存上用游标控制分配,alloc一块内存指针就移动固定位数,最后统一释放。这样,在操作系统看来,就总是去申请很大一块内存,并且造成碎片的几率很低,速度也快。


        这种实现方式不会让用户去free,因为free了也没用,池子并不会服用。但是这块大内存的生命周期不会很长,所以一般场景下不影响。下一小节会介绍"高级"一点的实现的方式,通过动态的拆分和合并来管理不同大小的内存。

        废话不多说,直接上代码:

typedef struct _mempool simple_mempool;

struct _mempool {
    uint32_t size;      // memory pool total size (512KB * n)
    void *raw_area;
    void *cursor;       // indicate the current position of pool
};
        内存池结构体句柄,保存大小、游标,和原始malloc指针。


/**
 * Don't allocate more than 512M space, because this mempool
 * just implement simple way of pool, it don't free anything
 * util call simple_mempool_destroy(), this feature is based 
 * on JUST USE it in an funtion or in one class
 */
void* simple_mempool_create(uint32_t size)
{
    if (size==0 || size>=1024*512)
        return NULL;

    // align of 4 byte
    // size += size % 4;

    simple_mempool *pool = (simple_mempool*)calloc(1,sizeof(simple_mempool));
    pool->size = CHUNK_SIZE*size;
    pool->raw_area = calloc(1,1024*size);
    pool->cursor = pool->raw_area;

    return pool;
}
         创建内存池,如果大于512M就忽略,建议使用高级内存池。


uint8_t simple_mempool_could_allocate(simple_mempool* pool, uint32_t n)
{
    // cursor will out of the end
    if ((pool->cursor-pool->raw_area)+n > pool->size)
        return 0;
    else    
        return 1;
}

void* simple_mempool_allocate(simple_mempool* pool, uint32_t n)
{
    // no space here
    if (NULL==pool || NULL==pool->raw_area || !simple_mempool_could_allocate(pool,n))
        return NULL;

    void* ret = pool->cursor;
    // move the cursor
    pool->cursor = (void*)((char*)pool->cursor + n);

    return ret;
}
         实际分配函数,只是挪动了一下cursor指针而已。


uint32_t simple_mempool_left(simple_mempool *pool)
{
    if (NULL == pool)
        return -1;
    else return pool->size - (pool->cursor - pool->raw_area);
}
         查看剩余量,此处pool->size / pool->cursor - pool->raw_area等是无符号整型,虽然没做边界校验,但是allocate函数保证了cursor不会超过size。

void simple_mempool_destroy(simple_mempool* pool)
{
    free(pool->raw_area);
    pool->cursor = pool->raw_area = NULL;   
    pool->size = 0;
}
         释放内存池,pool句柄可复用。


        下面是ut单侧的代码,分配完了就destroy并退出 :

#define ut_main main
int ut_main()
{

    simple_mempool *pool = simple_mempool_create(1);

    while(1) {
        long long *tmp = simple_mempool_allocate(pool,sizeof(long long)); 
        if (NULL == tmp) {
            printf("no space in mempool , destroy it !!!");
            simple_mempool_destroy(pool);
            break;  
        }       
    }

    return 0;
}

         周末我会把第2种实现的比较良好的内存池的实现方式贴上来,大家一起讨论。



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在Unity中实现内存可以提高游戏的性能和稳定性。以下是一些常见的内存技巧: 1. 使用对象池:对象池是一种重复使用对象的技术,可以避免频繁地创建和销毁对象,从而减少内存分配和垃圾回收的开销。 2. 减少资源加载:尽量避免在运行时频繁加载资源,可以通过预加载、异步加载、动态加载等方式优资源管理。 3. 优纹理使用使用合适的压缩格式和分辨率来减小纹理的内存占用,避免同时加载过多的高分辨率纹理。 4. 减少不必要的引用:及时释放不再使用的对象和资源,并确保没有循环引用导致无法释放的内存泄漏。 5. 使用内存工具:Unity提供了一些内存工具和分析器,如Profiler和Memory Profiler,可以帮助你检测和解决内存泄漏和性能问题。 6. 避免频繁的实例和销毁:尽量重用对象,避免频繁地实例和销毁大量对象,可以使用对象池或者对象复用技术。 7. 限制使用动态内存分配:尽量避免频繁地使用动态内存分配函数(如new和malloc),可以使用对象池或者预分配内存的方式来减少动态内存分配的次数。 8. 优代码逻辑:优算法和代码逻辑,减少不必要的计算和内存消耗。 这些只是一些常见的内存技巧,具体的优策略还需要根据具体的项目需求和情况来进行调整和实施。同时,使用性能分析工具和测试工具来评估和验证优效果也是很重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值