源战役客户端
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

127 行
4.3 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using MemoryProfilerWindow;
  6. using UnityEditor.MemoryProfiler;
  7. using UnityEngine;
  8. namespace MemoryProfilerWindow
  9. {
  10. class ShortestPathToRootFinder
  11. {
  12. private readonly CrawledMemorySnapshot _snapshot;
  13. public ShortestPathToRootFinder(CrawledMemorySnapshot snapshot)
  14. {
  15. _snapshot = snapshot;
  16. }
  17. public ThingInMemory[] FindFor(ThingInMemory thing)
  18. {
  19. var seen = new HashSet<ThingInMemory>();
  20. var queue = new Queue<List<ThingInMemory>>();
  21. queue.Enqueue(new List<ThingInMemory> { thing});
  22. while (queue.Any())
  23. {
  24. var pop = queue.Dequeue();
  25. var tip = pop.Last();
  26. string reason;
  27. if (IsRoot(tip, out reason))
  28. return pop.ToArray();
  29. foreach (var next in tip.referencedBy)
  30. {
  31. if (seen.Contains(next))
  32. continue;
  33. seen.Add(next);
  34. var dupe = new List<ThingInMemory>(pop) {next};
  35. queue.Enqueue(dupe);
  36. }
  37. }
  38. return null;
  39. }
  40. public bool IsRoot(ThingInMemory thing, out string reason)
  41. {
  42. reason = null;
  43. if (thing is StaticFields)
  44. {
  45. reason = "Static fields are global variables. Anything they reference will not be unloaded.";
  46. return true;
  47. }
  48. if (thing is ManagedObject)
  49. return false;
  50. if (thing is GCHandle)
  51. return false;
  52. var nativeObject = thing as NativeUnityEngineObject;
  53. if (nativeObject == null)
  54. throw new ArgumentException("Unknown type: " + thing.GetType());
  55. if (nativeObject.isManager)
  56. {
  57. reason = "this is an internal unity'manager' style object, which is a global object that will never be unloaded";
  58. return true;
  59. }
  60. if (nativeObject.isDontDestroyOnLoad)
  61. {
  62. reason = "DontDestroyOnLoad() was called on this object, so it will never be unloaded";
  63. return true;
  64. }
  65. if ((nativeObject.hideFlags & HideFlags.DontUnloadUnusedAsset) != 0)
  66. {
  67. reason = "the DontUnloadUnusedAsset hideflag is set on this object. Unity's builtin resources set this flag. Users can also set the flag themselves";
  68. return true;
  69. }
  70. if (nativeObject.isPersistent)
  71. return false;
  72. if (IsComponent(nativeObject.classID))
  73. {
  74. reason = "this is a component, living on a gameobject, that is either part of the loaded scene, or was generated by script. It will be unloaded on next scene load.";
  75. return true;
  76. }
  77. if (IsGameObject(nativeObject.classID))
  78. {
  79. reason = "this is a gameobject, that is either part of the loaded scene, or was generated by script. It will be unloaded on next scene load if nobody is referencing it";
  80. return true;
  81. }
  82. if (IsAssetBundle(nativeObject.classID))
  83. {
  84. reason = "this object is an assetbundle, which is never unloaded automatically, but only through an explicit .Unload() call.";
  85. return true;
  86. }
  87. reason = "This object is a root, but the memory profiler UI does not yet understand why";
  88. return true;
  89. }
  90. private bool IsGameObject(int classID)
  91. {
  92. return _snapshot.nativeTypes[classID].name == "GameObject";
  93. }
  94. private bool IsAssetBundle(int classID)
  95. {
  96. return _snapshot.nativeTypes[classID].name == "AssetBundle";
  97. }
  98. private bool IsComponent(int classID)
  99. {
  100. var packedNativeType = _snapshot.nativeTypes[classID];
  101. if (packedNativeType.name == "Component")
  102. return true;
  103. var baseClassID = packedNativeType.nativeBaseTypeArrayIndex;
  104. return baseClassID != -1 && IsComponent(baseClassID);
  105. }
  106. }
  107. }