如何从崩溃日志判定:是 CollectGarbage 回收了对象?
本文是 MuJoCo XML 导入崩溃:Datasmith GC 回收导入对象(UE4.26) 的补充说明,回答:
为什么日志里只有一行
Unhandled Exception: SIGSEGV: invalid attempt to read memory at address 0x00000000e30a0490,就能判断是CollectGarbage()把导入时创建的对象回收了?
1. 地址本身能说明什么
Unhandled Exception: SIGSEGV: invalid attempt to read memory at address 0x00000000e30a0490
- 这是 read(不是 write)——代码在读取某个对象的内存;
- 地址不是 0 附近:纯空指针解引用通常读
0x0、0x8、0x10这类小地址; 0x00000000e30a0490是「看起来像指针、实际不可映射」的垃圾值,典型于对象已释放、内存被分配器改写后,代码又通过它读 vtable 或成员;- 同一地址在多次崩溃中完全一致(11-05 的三次崩溃都是
0xe30a0490),说明是确定性的释放后内存内容,而不是随机野指针。
但这只能证明「use-after-free 类野指针」,不能证明是谁释放的。 是谁释放的,要看下面的证据。
2. 证据详解
2.1 崩溃栈:对象死在 ImportObject 期间
崩溃时的调用栈(节选):
UAssetToolsImpl::ImportAssetsInternal ← 崩溃点(ResolveSupportedClass)
UAssetToolsImpl::ImportAssetTasks
UMujocoGenerationAction::AttemptMeshImport
UMujocoGenerationAction::ImportSingleMesh
UMujocoGenerationAction::ImportNodeRecursive
...
UMujocoImportFactory::FactoryCreateFile
UFactory::ImportObject ← 工厂调用在这里面
UAssetToolsImpl::ImportAssetsInternal ← 外层(拖入的 .xml)
FImportFilesByPath::Run
UImportSubsystem::HandleNextTick
关键推理:
- 在同一个
ImportAssetsInternal里,Factory在调用ImportObject之前刚被正常使用过(Factory->ImportObject(...)本身能调进去); - 调用返回后,下一次使用同一个
Factory(Factory->ResolveSupportedClass())就崩溃了; - 指针值没有变化(不是传错指针),唯一解释是:对象在
ImportObject执行期间被销毁了。
2.2 日志时序:窗口内只发生了 Datasmith 的 GC
崩溃前最后几行日志:
LogUObjectHash: Compacting FUObjectHashTables data took 2.88ms
LogDatasmithImport: Imported z1_Link00 in [0 min 2.070 s]
LoadErrors: Warning: Mesh has primitives with no materials assigned: 0_z1_Link00.stl
=== Critical error ===
Unhandled Exception: SIGSEGV: invalid attempt to read memory at address 0x00000000e30a0490
查看源码可知, 这一行是在 CollectGarbage() 之后才打印的:
// DatasmithImportFactory.cpp:340 ReportImportStats
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); // :349 ← 显式 GC
...
UE_LOG(LogDatasmithImport, Log, TEXT("%s %s in [%d min %.3f s]%s"), ImportContext.bIsAReimport ? TEXT("Reimported") : TEXT("Imported"), ImportContext.Scene->GetName(), ElapsedMin, ElapsedSeconds, *MemoryStats);
因此「日志紧挨着崩溃」=「GC 刚跑完,控制权回到 AssetTools,随即崩溃」。
也可以在源码里全局搜这个格式串
grep -rn 'in \[%d min'
/home/ubuntu/UnrealEngine_4.26/Engine/Plugins/Enterprise/DatasmithImporter/Source --include=*.cpp
输出
/home/ubuntu/UnrealEngine_4.26/Engine/Plugins/Enterprise/DatasmithImporter/Source/DatasmithImporter/Private/DatasmithImportFactory.cpp:366: UE_LOG(LogDatasmithImport, Log, TEXT("%s %s in [%d min %.3f s]%s"), ImportContext.bIsAReimport ? TEXT("Reimported") : TEXT("Imported"), ImportContext.Scene->GetName(), ElapsedMin, ElapsedSeconds, *MemoryStats);