Contents

UE4 从UProperty到FProperty

UE4 在4.25中,进行了一些非常重要的改进。 其中就有FProperty。

一.老旧的结构体系

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524192500.png

UE4中带有前缀U的类是UObject派生类。每个UObject都有一个与之对应的UClass,这个UClass保存了所有的反射系统相关的信息,描述了各个Property之间的内存布局和关系;通过UClass可以遍历所有的序列化属性;通过Object对象的实例化地址就可以将相应的Property的值取出来,进行读写操作。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524193107.png

UClass保留了这个对象的结构信息。它在内部拥有成员的元素列表,例如UFunction,UEnum,UProperty等。它们一起作用来提供“反射”机制。从命名不难看出UClass 和下文中的UProperty,都是从UObject继承而来,主要是为了使用Object的GC功能。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524193843.png

UProperty将变量定义为类的组成部分。这也是我们这次的重点内容。 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524194035.png

不管我们是在蓝图中还是在C++中,属性都是由我们的UProperty来指定的。这些属性包括蓝图变量和节点,以及执行节点的返回值。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524194351.png

二.反射

我们将C++编译成exe文件。编译器将C++中的信息翻译成了机器语言。我们本身的函数名称在编译时将会被替换和省略。因此你不能在自己的程序中使用字符串"HogeHogeFunc"来处理任何事情。反射是静态或者动态的去构造这一映射信息,并且在运行时使用他们。UE4是静态反射的。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524195002.png

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524195207.png

在UE4中,我们在通过他特殊的宏,将所需要反射的数据进行标记,从而自动的生成供运行时查询的信息。 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524195811.png

从而其生成了一些额外的信息。 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524200008.png

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524200239.png

三.反射案例

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524200507.png

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524200600.png

四.FProperty

在创建类时,会生成大量属性,包括蓝图类。有些类型将可能有几十万多个UProperty,因为所有的UProperty继承自UObject,因此会产生各种各样的开销。这一特性对整个引擎影响及其广泛,包括额外的内存空间,UProperty构建/销毁成本,垃圾回收性能。

从4.25开始,此UProperty已完全更改为FProperty。 前缀“F”说明其不再继承UObject。UProperty类的定义仍然存在,但它只用于在将早期版本中创建的资源转换为FProperty做一次。

这是4.24的继承关系。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524201316.png

这是4.25的继承关系

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524201406.png

由于Field与UObject和UField大多数函数拥有相同的名称,因此当您更新引擎时,只需将其从UxxProperty重命名为FxxProperty即可。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524201611.png

五.改善点

内存消耗减少

在整个应用程序中使用的UObject中内存占用中,Property占40%以上,根据情况也有超过60%的程度。特别是在包含多个函数调用的蓝图很多的情况下。在ThirdPersonTemplate中,UE4.24的UObject合计有5万多个,其中70%左右是Property。这些消耗直接没了。 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524202433.png

由于继承了UObject,因此每个属性不再需要超过100个字节的额外内存。 虽然每个容量都是微乎其微的,但由于数量众多,有时会减少数十MByte或更多的内存使用量。

使用宏调用8个BoolProperty返回值的函数2304次。 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524202637.png https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524203212.png

如前所述,由于不适用NewObject而是C++的New和Delete,因此生成和销毁特性也变得简单和快速。同样,您还可以缩短应用程序的启动时间。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524203700.png https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524203717.png https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210524203743.png

六.结论

4.25 UProperty变成了FProperty

  1. 继承UObject后的开销不见了
  2. 提高了引擎启动时间
  3. GC处理时间明显改善
  4. 内存使用量的减少
  5. 打包后包体体积减少