虚幻引擎MemReport工具使用笔记
- 虚幻引擎可以用指令
MemReport -full
来输出一份内存报告。生成的内存报告路径一般在:`Project\Saved\Profiling\MemReports\ 下。 - 这份报告里我们可以看到虚幻引擎各种资源在内存里的大小,以及部分资源信息,例如:贴图大小、贴图格式等。
- 对于很多资源我们可以看到这样的格式:
在代码里面,这些数据是这样输出的:
从代码里面不难看出后四列的含义:总内存占用、专用系统内存占用、专用显存占用、未知的内存占用。但是前两列的含义就不清晰了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49...
if (bCSV)
{
Ar.Logf(TEXT(",Object,NumKB,MaxKB,ResExcKB,ResExcDedSysKB,ResExcDedVidKB,ResExcUnkKB"));
}
else
{
Ar.Logf(
TEXT("%140s %10s %10s %10s %15s %15s %15s"),
TEXT("Object"),
TEXT("NumKB"),
TEXT("MaxKB"),
TEXT("ResExcKB"),
TEXT("ResExcDedSysKB"),
TEXT("ResExcDedVidKB"),
TEXT("ResExcUnkKB")
);}
for (const FSubItem& ObjItem : Objects)
{
if (bCSV)
{ Ar.Logf(
TEXT(",%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f"),
*ObjItem.Object->GetFullName(),
ObjItem.Num / 1024.0f,
ObjItem.Max / 1024.0f,
ObjItem.TrueResourceSize.GetTotalMemoryBytes() / 1024.0f,
ObjItem.TrueResourceSize.GetDedicatedSystemMemoryBytes() / 1024.0f,
ObjItem.TrueResourceSize.GetDedicatedVideoMemoryBytes() / 1024.0f,
ObjItem.TrueResourceSize.GetUnknownMemoryBytes() / 1024.0f
);
} else
{
Ar.Logf(
TEXT("%140s %10.2f %10.2f %10.2f %15.2f %15.2f %15.2f"),
*ObjItem.Object->GetFullName(),
ObjItem.Num / 1024.0f,
ObjItem.Max / 1024.0f,
ObjItem.TrueResourceSize.GetTotalMemoryBytes() / 1024.0f,
ObjItem.TrueResourceSize.GetDedicatedSystemMemoryBytes() / 1024.0f,
ObjItem.TrueResourceSize.GetDedicatedVideoMemoryBytes() / 1024.0f,
ObjItem.TrueResourceSize.GetUnknownMemoryBytes() / 1024.0f
);
if (bVerboseObjectOutput)
{ ObjItem.TrueResourceSize.LogSummary(Ar);
} }}
...
继续追踪代码,实际上ObjItem
关于NumKB和MaxKB的内存信息是由类FArchiveCountMem
收集的。观察FArchiveCountMem
的实现:不难看出一般是在UObject的某个和序列化相关的函数中统计的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class FArchiveCountMem : public FArchiveUObject
{
public:
FArchiveCountMem( UObject* Src, bool bFilterEditorOnly = false )
: Num(0)
, Max(0)
{ ArIsCountingMemory = true;
ArIsFilterEditorOnly = bFilterEditorOnly;
if( Src )
{ Src->Serialize( *this );
} } SIZE_T GetNum() const
{
return Num;
} SIZE_T GetMax() const
{
return Max;
}
virtual void CountBytes( SIZE_T InNum, SIZE_T InMax ) override
{
Num += InNum;
Max += InMax;
} /**
* Returns the name of the Archive. Useful for getting the name of the package a struct or object * is in when a loading error occurs. * * This is overridden for the specific Archive Types **/ virtual FString GetArchiveName() const override { return TEXT("FArchiveCountMem"); }
protected:
SIZE_T Num, Max;
};至此,我们可以得出结论:一般来说,NumKB和MaxKB的内存信息是统计被UPROPERTY宏标记的成员占用的内存。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void UObject::Serialize(FStructuredArchive::FRecord Record)
{
...
// Memory counting (with proper alignment to match C++)
SIZE_T Size = GetClass()->GetStructureSize();
UnderlyingArchive.CountBytes(Size, Size);
...
}
/** Returns actual allocated size of structure in memory */
FORCEINLINE int32 GetStructureSize() const
{
return Align(PropertiesSize,MinAlignment);
}
另外的情况就是涉及到网络或者Serialize(FStructuredArchive::FRecord Record)
被重写的情况,通过查找CountBytes
的引用,发现很多涉及到网络相关数据大小的统计也用到了这玩意。因此,具体含义可能需要具体分析,但一般情况可以默认为被UPROPERTY宏标记的成员占用的内存。