Skip to content

Commit 31e1d84

Browse files
committed
Log if an object is itself a LMS in the retention path
1 parent b717d76 commit 31e1d84

File tree

2 files changed

+53
-25
lines changed

2 files changed

+53
-25
lines changed

UMS.Analysis/Structures/Objects/ManagedClassInstance.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,17 @@ private void AppendRetentionReason(StringBuilder sb, SnapshotFile file, ManagedC
262262
var field = fieldList.First(f => f.FieldIndex == child.FieldIndexOrArrayOffset);
263263
sb.Append("Field ").Append(file.GetFieldName(field.FieldIndex)).Append(" of ");
264264
sb.Append(parentName).Append(" at 0x").Append(parent.ObjectAddress.ToString("X"));
265+
266+
if (parent.InheritsFromUnityEngineObject(file))
267+
{
268+
var parentInst = file.GetOrCreateManagedClassInstance(parent.ObjectAddress);
269+
270+
if (parentInst.HasValue && parentInst.Value.IsLeakedManagedShell(file))
271+
sb.Append(" (leaked managed shell)");
272+
else
273+
sb.Append(" (unity object, non-leaked)");
274+
}
275+
265276
sb.Append(" <- ");
266277
break;
267278
}
@@ -277,4 +288,34 @@ private void AppendRetentionReason(StringBuilder sb, SnapshotFile file, ManagedC
277288
throw new ArgumentOutOfRangeException(nameof(child), "Invalid LoadedReason");
278289
}
279290
}
291+
292+
public bool IsLeakedManagedShell(SnapshotFile file)
293+
{
294+
if (!InheritsFromUnityEngineObject(file))
295+
//Can't be a leaked managed shell if it's not a managed shell at all
296+
return false;
297+
298+
// if (Fields == null)
299+
// return false; //Can't check
300+
301+
var fields = file.GetInstanceFieldInfoForTypeIndex(TypeInfo.TypeIndex);
302+
for (var fieldNumber = 0; fieldNumber < fields.Length; fieldNumber++)
303+
{
304+
var basicFieldInfoCache = fields[fieldNumber];
305+
var name = file.GetFieldName(basicFieldInfoCache.FieldIndex);
306+
307+
if (name == "m_CachedPtr")
308+
{
309+
var value = Fields[fieldNumber];
310+
311+
if (value is not IntegerFieldValue integerFieldValue)
312+
throw new Exception("Expected integer field value");
313+
314+
return integerFieldValue.Value == 0;
315+
}
316+
}
317+
318+
//Couldn't find the m_CachedPtr field. Weird, but return false.
319+
return false;
320+
}
280321
}

UnityMemorySnapshotThing/Program.cs

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -87,36 +87,21 @@ private static void FindLeakedUnityObjects(SnapshotFile file)
8787
var leakedTypes = new Dictionary<string, int>();
8888
foreach (var managedClassInstance in unityEngineObjects)
8989
{
90-
var fields = file.GetInstanceFieldInfoForTypeIndex(managedClassInstance.TypeInfo.TypeIndex);
91-
for (var fieldNumber = 0; fieldNumber < fields.Length; fieldNumber++)
90+
if (managedClassInstance.IsLeakedManagedShell(file))
9291
{
93-
var basicFieldInfoCache = fields[fieldNumber];
94-
var name = file.GetFieldName(basicFieldInfoCache.FieldIndex);
92+
var typeName = file.GetTypeName(managedClassInstance.TypeInfo.TypeIndex);
9593

96-
if (name == "m_CachedPtr")
97-
{
98-
var value = managedClassInstance.Fields[fieldNumber];
99-
100-
if(value is not IntegerFieldValue integerFieldValue)
101-
throw new Exception("Expected integer field value");
102-
103-
if (integerFieldValue.Value == 0)
104-
{
105-
var typeName = file.GetTypeName(managedClassInstance.TypeInfo.TypeIndex);
94+
str = $"Found leaked managed object of type: {typeName} at memory address 0x{managedClassInstance.ObjectAddress:X}";
95+
Console.WriteLine(str);
96+
ret.AppendLine(str);
10697

107-
str = $"Found leaked managed object of type: {typeName} at memory address 0x{managedClassInstance.ObjectAddress:X}";
108-
Console.WriteLine(str);
109-
ret.AppendLine(str);
110-
111-
str = $" Retention Path: {managedClassInstance.GetFirstObservedRetentionPath(file)}";
112-
Console.WriteLine(str);
113-
ret.AppendLine(str);
98+
str = $" Retention Path: {managedClassInstance.GetFirstObservedRetentionPath(file)}";
99+
Console.WriteLine(str);
100+
ret.AppendLine(str);
114101

115-
leakedTypes[typeName] = leakedTypes.GetValueOrDefault(typeName) + 1;
102+
leakedTypes[typeName] = leakedTypes.GetValueOrDefault(typeName) + 1;
116103

117-
numLeaked++;
118-
}
119-
}
104+
numLeaked++;
120105
}
121106
}
122107

@@ -131,4 +116,6 @@ private static void FindLeakedUnityObjects(SnapshotFile file)
131116

132117
File.WriteAllText("leaked_objects.txt", ret.ToString());
133118
}
119+
120+
134121
}

0 commit comments

Comments
 (0)