(UE4 4.26)UE4 C++ FMemory内存管理从入门到深入

UE4 内存管理--FMemory简介

FMemory是UE4内存分配经常使用的类, 虽然使用UObject我们并没有直接使用到FMemory,但是UObject的内存分配底层机制上确实是使用了FMemory。并且在UE4编程中,非UObject的结构体,我们尽量不使用New,Delete来管理C++内存,取而代之的是使用 FMemory::Malloc FMemory::Free

示例代码:

struct TestMemory
{
	int32 a;
	float b;
	bool c;
	int32 d;
};

TestMemory* testPtr = nullptr;
testPtr = (TestMemory*)FMemory::Malloc(sizeof(TestMemory));
FMemory::Free(testPtr);

UE4 内存管理--FMemory深入

FMemory分配内存的内存管理器来自于static FMalloc* GMalloc;

GMalloc的创建来源于

平台内存管理类 FPlatformMemory 是专门管理各个平台内存管理器的类

比如 在PC端我们一般是用FWindowsPlatformMemory

这里值得注意的一个关键类是FMalloc, 这个是内存分配核心基类, 定义了void* Malloc()void Free(void*)等底层接口

FMalloc的子类FMallocTBB,FMallocBinned,FMallocBinned2,FMallocBinne3,FMallocBinnedArena等覆盖基类Malloc和Free方法提供了真正的内存分配方式。比如FMallocTBB采用的内存分配器是因特尔TBB内存管理器,而MallocBinned系列核心是基于内存池片段的分配策略。

总之UE4的各种继承FMallocFMallocXXX类都是提供了各种策略的内存分配器,

回到上面FPlatformMemory::BaseAllocator()其实是相应平台根据各种条件最终会创建相应的一个对应分配器,以FWindowsPlatformMemory为例子:

 

 下面具体分析下FMallocBinned2这个分配器的内存分配策略

FMallocBinned2内存分配器

FMallocBinned2分配器的策略概括为小内存分配大内存分配两种情况

小内存分配

小内存:预先分配BINNED2_SMALL_POOL_COUNT(45) 个内存池, 每个内存池的块大小在SmallBlockSizes数组找得到:

可以简略的认为大概是45个内存池, 从16字节到32768 - 16字节,当你要求分配一块内存的时候,如果是小内存(大小小于32768 - 16), 就找到相应大小的内存池进行内存块的分配,比如你申请34字节大小的内存,则从SmallBlockSizes找到的就是48字节的内存池,PoolIndex为2.

                                                                                                                                                        顺便提一点,UE4在查找相应的内存池索引上做了相应的优化, 就是建立一个内存池索引查询表(2048大小的数组), 能根据申请内存的大小快速找到相应的内存池索引。 

 大内存分配

下面看出申请不同大小的内存存在两种不同的策略

 

大内存: 使用系统内存页分配器

 

两个关键宏

BINNED2_MAX_CACHED_OS_FREES 64
BINNED2_MAX_CACHED_OS_FREES_BYTE_LIMIT 64*1024*1024

TCachedOSPageAllocator本质上就是个带着缓存机制的内存分配器,最底层分配逻辑对应不同平台存在不同的实现,比如Windows系统:

VirtualAlloc就是Windows平台分配内存的底层API

这里着重说下 缓存机制, 所谓缓存机制就是缓存多个BINNED2_MAX_CACHED_OS_FREES(64)个内存块,每次申请新内存的时候就从缓存的空闲内存块中寻找有没有匹配大小的块,如果有就使用,没有就申请新的。

 至于缓存块是哪里来的?可以看释放内存的FreeImpl函数,当缓存总数目没达到BINNED2_MAX_CACHED_OS_FREES个时,会进行缓存,当然如果释放的总缓存内存块数和总缓存大小超过了规定的,则会进行适当的释放.

 资料参考

 【1】FMallocBinned内存分配器

         

    游戏引擎中之所以要做内存管理,一个是加快内存分配速度,另一个就是处理内存泄漏问题。     1.先简单说处理内存泄漏这个问题,一般的引擎在debug 模式下 都有一个记录内存分配的结构体,每分配一段内存就记录这段内存的信息,包括大小,分配时间,是否是数组,前后越界的标记等等吧,其实这些都不是那么重要,因为你只知道这些,一旦泄漏出现,你虽然知道泄漏,但无法定位。相反如果你知道堆栈的调用信息,就能准确定位。我以前的实现,在debug下,只记录当前调用new的时候的行号和文件,也就是内部的__FILE__ __LINE___.。我看了同事那个能记录堆栈调用过程,简直觉得很牛逼(其实不是调用堆栈,只是打印出调用过程,继续往下看你就知道了),以前自己也想过,但不知道怎么去实现。如果U3里面也加入这个功能,那就更牛叉了。思想很简单,就是核心东西在一个函数,这个是系统函数,提供当前这行指令所在的地址,它会打印出来这行指令的文件名和行号。先详细说下数据在内存的分配     最早的计算机数据段和代码段区分的很严格,现在似乎没有这么严格了!对于全局变量和静态变量它的分配完全在数据段分配,知道运行结束才会收回内存!而对于自动变量(包括函数参数和函数中定义的变量)则在堆栈中分配!一般的分配情形是这样的:从栈下到栈顶依次是函数参数,函数结束后下一条指令的地址,寄存器保护,然后是函数中定义的变量!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值