UE4的内存模型
转自:https://blog.csdn.net/noahzuo/article/details/73565259
UObject和FUObjectItem
UE4运行的基本单位是UObjet,然而UObject针对于内存相关的东西都储存在结构体FUObjectItem中。有个全局变量GUObjectArray,可以通过以下代码来遍历所有的Objects:
for (FRawObjectIterator It(false); It; ++It)
{
FUObjectItem* ObjectItem = *It;
UObject* obj = ObjectItem->Object;
}
可以通过如下代码来获得一个UObject对应的ObjectItem
FUObjectItem* ObjectItem = GUObjectArray.ObjectToObjectItem(Object);
GUObjectArray中有几个函数可以通过索引和ObjectItem、Object的相互获取,对应的函数为IndexToObject、ObjectToIndex、IndexToObjectUnsafeForGC等。
GUObjectArray中所有的UObjectArray的分布是有顺序的——那些不会被GC的UObject,例如各StaticClass、核心Object,GamePlayInstance等会放在前面;而那些有可能被GC的UObject,则放在后面。此外,GUObjectArray中有个变量ObjLastNonGCIndex,用于分隔这两类UObject。
/**
* Returns true if this object is "disregard for GC"...same results as the legacy RF_DisregardForGC flag
*
* @param Object object to get for disregard for GC
* @return true if this object si disregard for GC
*/
FORCEINLINE bool IsDisregardForGC(const class UObjectBase* Object)
{
return Object->InternalIndex <= ObjLastNonGCIndex;
}
FUObjectCluster相关
Cluster指得是一组UObject为一簇,这群UObject同生共死,每个Cluster有一个根root的UObject。
每一个FUObjectItem里面有一个变量ClusterRootIndex,这个储存的是当前Object所在的Cluster的root object所在GUObjectArray的索引。
// UObjectArray.h
// UObject Owner Cluster Index
int32 ClusterRootIndex;
引擎中有一个全局变量FUObjectClusterContainer GUObjectClusters,用于管理内存中所有的Clusters。
// Get the number of all clusters that have been allocated.
GUObjectClusters.GetNumAllocatedClusters()
但很奇怪的,在我新建的若干个测试关卡/项目中,这个值一直为0……
- 一个关卡
ULevel不可以成为一个Cluster的root,原因是在这个时候(postload之后)仍然有很多被Level引用的assets并未构建它们自己的Cluster。
bool ULevel::CanBeClusterRoot() const
{
// We don't want to create the cluster for levels in the same place as other clusters (after PostLoad)
// because at this point some of the assets referenced by levels may still haven't created clusters themselves.
return false;
}
虽然ULevel本身不可以作为Cluster Root,而相反的是它会创建一个特殊的actor container,用来储存原本应该位于Cluster的actors。这是由于只有某些特殊的actor种类才能用于Cluster,所以剩下的那些不能被cluster的actors需要通过actor container来进行引用。
ULevel中使用ClusterActors数组用于储存那些用于Cluster的Actors;用ActorsForGC储存那些剩下的Actors。主食中提到不希望Level直接去引用那些本就是Cluster的Actors,注释中提到这会导致变慢(针对于cluster的Reference很慢,可能是如果引用了cluster里面的actor,那么会导致整个cluster也会添加对应的引用关系,从而导致引用的层级变多吧……)
TArray<AActor*> ClusterActors;
for (int32 ActorIndex = Actors.Num() - ; ActorIndex >= ; --ActorIndex)
{
AActor* Actor = Actors[ActorIndex];
if (Actor && Actor->CanBeInCluster())
{
ClusterActors.Add(Actor);
}
else
{
ActorsForGC.Add(Actor);
}
}
引用相关
- 如何获得一个
UObject所引用的其他UObject?
TArray<UObject*> CollectedReferences;
FReferenceFinder ObjectReferenceCollector(CollectedReferences);
ObjectReferenceCollector.FindReferences(Object);
一度看了看Reference是怎么跑起来的,后来发现大部分的从UClass派生出来的类会制定对应的ClassAddReferenceObjects方法,这个方法用于制定该类会和哪些东西产生对应的引用……
不受内存管理的内存
- malloc & free
- new & delete
new与malloc的区别在于,new在分配内存完成之后会调用构造函数。
内存管理的内存
- 对于不是继承自UObject的Native C++类,使用TSharedPtr、TAutoPtr、TWeakPtr、TSharedRef、TScopedPointer管理
- 对于继承自UObject的子类
创建: UObject::NewObject<> 或是 UObject::ConstructObject<>,其中ConstructObject可以做更复杂的参数配置
销毁:当计数为0时,自动释放;调用UObject::ConditionalBeginDestroy()手动释放。若要强制调用垃圾回收,则调用UWorld::ForceGarbageCollection(true)。 - 对于继承自AActor的子类
创建: UWorld::SpawnActor<>
销毁: AActor::Destroy() - TArray<>数组需要用UPROPERTY()修饰,否则会导致内存管理错误
- 继承自UActorComponent的组件,使用AActor::CreateDefaultSubobject<>,同样组件的指针变量也需要用UPROPERTY()修饰。
1.什么样的对象可以被unreal engine管理和回收:
unreal engine定义的类中,只有UObject或者是UObject的派生类创建的对象,才能被unreal engine管理,用完后才能被unreal engine回收。其它类比如:UStructs,不具有这个特性。
2.UObject或者是UObject的派生类的实例,创建和销毁的方式:
1).AActor类或者AActor派生类,虽然也是UObject的派生类,但创建和销毁方式不同于一般UObject的派生类:
AActor创建方式:
UWorld::SpawnActor() //此方法创建Actor实例后,UWorld会持有Actor实例的引用
AActor销毁的方式:
AActor::Destroy() //此方法会将Actor实例从关卡中删除,并将Actor实例标记为“待杀死”,然后会在下一次GC时删除
2).除AActor类或者AActor派生类以外的其它UObject或者是UObject的派生类:
UObject可通过如下4种方式创建:
NewObject<class>()
NewNamedObject<class>()
ConstructObject<class>()
new
UObject销毁方式:
UObject::MarkPendingKill() //此方法执行后,所有指向此实例的指针将设置为NULL,并在下一次GC时删除
3.垃圾收集器如何管理UObject的实例
1).AActor类或者AActor派生类的实例被创建后,会自动存放在垃圾收集器的对象根集合中,不会被自动回收。
2).除AActor类或者AActor派生类以外的其它UObject或者是UObject的派生类的实例被创建后,会自动被回收,如果想不被GC回收,主要有如下几种方式:
2.1).创建的实例作为UObject的派生类的成员变量,并且被标记为UPROPERTY()
2.2).创建的实例存放在TArray中,TArray作为UObject的派生类的成员变量,并且被标记为UPROPERTY()
2.3).创建的实例存放在智能指针中。(此说法待验证)
2.4).通过UObject::AddToRoot(),设置RF_RootSet标志(可参考:UObject Instance Creation)。
UE4的内存模型的更多相关文章
- Java内存模型深度解析:总结--转
原文地址:http://www.codeceo.com/article/java-memory-7.html 处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会 ...
- JVM学习(3)——总结Java内存模型
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 为什么学习Java的内存模式 缓存一致性问题 什么是内存模型 JMM(Java Memory Model)简 ...
- 浅析java内存模型--JMM(Java Memory Model)
在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步? 在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的. 线程之间通过共享程序公共的状态,通 ...
- JMM(java内存模型)
What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...
- 《深入理解Java内存模型》读书总结
概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...
- java内存模型(待完善)
JMM 1.内存模型的抽象. 本地内存是JMM的一个抽象概念,并不是真实存在,它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化. 2.内存可见性问题? ? 3.重排序 编译器优化重排序 ...
- Java内存模型及性能优化
最近在做一个项目的性能优化,遇到好多以前没有关注过的性能问题,一头雾水,今天做个笔记,简单记录下JVM相关的参数设置. 一.JVM内存模型 首先介绍下Java程序具体执行的过程: Java源代码文件( ...
- C++11 并发指南七(C++11 内存模型一:介绍)
第六章主要介绍了 C++11 中的原子类型及其相关的API,原子类型的大多数 API 都需要程序员提供一个 std::memory_order(可译为内存序,访存顺序) 的枚举类型值作为参数,比如:a ...
- Java内存模型深度解析:final--转
原文地址:http://www.codeceo.com/article/java-memory-6.html 与前面介绍的锁和Volatile相比较,对final域的读和写更像是普通的变量访问.对于f ...
随机推荐
- Winform异常处理之ThreadException、unhandledException及多线程异常处理
异常处理之ThreadException.unhandledException及多线程异常处理 一:ThreadException和unhandledException的区别 处理未捕获的异常是每个应 ...
- shortcuts for contructor 创建对象捷径
- c#中的继承学习总结
c#的继承方法,大体上和c++的类似,但是有点区别的,我这里刚刚初学,因此把重点记录下. 1.派生类继承了父类,那么,如果父类的方法和数据都是public,那么派生类都会继承.派生类可以直接调用父类的 ...
- SpringBoot源码分析-编译环境与新建测试模块
建议 分析源码建议不要使用Idea或者Eclipse等IDE工具的反编译功能或者导入源码包的方式看源码,那样不能给框架的源码做注释,所以分析源码之前都得先下载源码并构建,然后在项目中新建一个Modul ...
- elasticsearch安装和部署
1.可以在官网上下载不同版本的es,官网地址为:https://www.elastic.co/cn/downloads/past-releases#elasticsearch 2.解压elastics ...
- SQL必知必会收集学习
1.按查询列位置排序:如按第一列 降序排序 desc
- Linux上使用Windows软件
小书匠 安装完成后,甚至可以在linux上进行视频会议,整个过程分两个步骤: 1.安装deepin-wine 这个步骤看github,Jactor Sue这位老哥弄好了,在这: Deepin-Apps ...
- HTML5之图片在Retina屏的常用几种处理方式
Media Queries使用css3的媒体查询实现高清屏的图片处理. @media only screen and (-webkit-min-device-pixel-ratio: 1.5), on ...
- mysql开放远程连接
1.检查端口是否被监听,没有的话请启动mysql. netstat -atnp | grep 3306 2.检查用户是否具备远程连接,即host字段值不是 % mysql -uroot -p你的密码 ...
- 你对SQA的职责和工作活动(如软件度量)的理解?
SQA就是独立于软件开发的项目组,通过对软件开发过程的监控,来保证软件的开发流程按照指定的CMM规程(如果有相应的CMM规程),对于不符合项及时提出建议和改进方案,必要时可以向高层经理汇报以求问题的解 ...