源战役客户端
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

372 lines
16 KiB

  1. using System;
  2. using Assets.Editor.Treemap;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using UnityEditor.MemoryProfiler;
  6. using System.Linq;
  7. using System.Collections.Generic;
  8. namespace MemoryProfilerWindow
  9. {
  10. public class Inspector
  11. {
  12. ThingInMemory _selectedThing;
  13. private ThingInMemory[] _shortestPath;
  14. private ShortestPathToRootFinder _shortestPathToRootFinder;
  15. private static int s_InspectorWidth = 400;
  16. Vector2 _scrollPosition;
  17. MemoryProfilerWindow _hostWindow;
  18. CrawledMemorySnapshot _unpackedCrawl;
  19. PrimitiveValueReader _primitiveValueReader;
  20. Dictionary<ulong, ThingInMemory> objectCache = new Dictionary<ulong, ThingInMemory>();
  21. private Texture2D _textureObject;
  22. private int _prevInstance;
  23. private float _textureSize = 128.0f;
  24. static class Styles
  25. {
  26. public static GUIStyle entryEven = "OL EntryBackEven";
  27. public static GUIStyle entryOdd = "OL EntryBackOdd";
  28. }
  29. GUILayoutOption labelWidth = GUILayout.Width(150);
  30. public Inspector(MemoryProfilerWindow hostWindow, CrawledMemorySnapshot unpackedCrawl, PackedMemorySnapshot snapshot)
  31. {
  32. _unpackedCrawl = unpackedCrawl;
  33. _hostWindow = hostWindow;
  34. _shortestPathToRootFinder = new ShortestPathToRootFinder(unpackedCrawl);
  35. _primitiveValueReader = new PrimitiveValueReader(_unpackedCrawl.virtualMachineInformation, _unpackedCrawl.managedHeap);
  36. }
  37. public float width
  38. {
  39. get { return s_InspectorWidth; }
  40. }
  41. public void SelectThing(ThingInMemory thing)
  42. {
  43. _selectedThing = thing;
  44. _shortestPath = _shortestPathToRootFinder.FindFor(thing);
  45. }
  46. public void Draw()
  47. {
  48. GUILayout.BeginArea(new Rect(_hostWindow.position.width - s_InspectorWidth, 25, s_InspectorWidth, _hostWindow.position.height - 25f));
  49. _scrollPosition = GUILayout.BeginScrollView(_scrollPosition);
  50. if (_selectedThing == null)
  51. GUILayout.Label("Select an object to see more info");
  52. else
  53. {
  54. var nativeObject = _selectedThing as NativeUnityEngineObject;
  55. if (nativeObject != null)
  56. {
  57. GUILayout.Label("NativeUnityEngineObject", EditorStyles.boldLabel);
  58. GUILayout.Space(5);
  59. EditorGUILayout.LabelField("Name", nativeObject.name);
  60. EditorGUILayout.LabelField("ClassName", nativeObject.className);
  61. EditorGUILayout.LabelField("ClassID", nativeObject.classID.ToString());
  62. EditorGUILayout.LabelField("instanceID", nativeObject.instanceID.ToString());
  63. EditorGUILayout.LabelField("isDontDestroyOnLoad", nativeObject.isDontDestroyOnLoad.ToString());
  64. EditorGUILayout.LabelField("isPersistent", nativeObject.isPersistent.ToString());
  65. EditorGUILayout.LabelField("isManager", nativeObject.isManager.ToString());
  66. EditorGUILayout.LabelField("hideFlags", nativeObject.hideFlags.ToString());
  67. EditorGUILayout.LabelField("hideFlags", nativeObject.size.ToString());
  68. DrawSpecificTexture2D(nativeObject);
  69. }
  70. var managedObject = _selectedThing as ManagedObject;
  71. if (managedObject != null)
  72. {
  73. GUILayout.Label("ManagedObject");
  74. EditorGUILayout.LabelField("Type", managedObject.typeDescription.name);
  75. EditorGUILayout.LabelField("Address", managedObject.address.ToString("X"));
  76. EditorGUILayout.LabelField("size", managedObject.size.ToString());
  77. if (managedObject.typeDescription.name == "System.String")
  78. EditorGUILayout.LabelField("value", StringTools.ReadString(_unpackedCrawl.managedHeap.Find(managedObject.address, _unpackedCrawl.virtualMachineInformation), _unpackedCrawl.virtualMachineInformation));
  79. DrawFields(managedObject);
  80. if (managedObject.typeDescription.isArray)
  81. {
  82. DrawArray(managedObject);
  83. }
  84. }
  85. if (_selectedThing is GCHandle)
  86. {
  87. GUILayout.Label("GCHandle");
  88. EditorGUILayout.LabelField("size", _selectedThing.size.ToString());
  89. }
  90. var staticFields = _selectedThing as StaticFields;
  91. if (staticFields != null)
  92. {
  93. GUILayout.Label("Static Fields");
  94. GUILayout.Label("Of type: " + staticFields.typeDescription.name);
  95. GUILayout.Label("size: " + staticFields.size);
  96. DrawFields(staticFields.typeDescription, new BytesAndOffset() { bytes = staticFields.typeDescription.staticFieldBytes, offset = 0, pointerSize = _unpackedCrawl.virtualMachineInformation.pointerSize}, true);
  97. }
  98. if (managedObject == null)
  99. {
  100. GUILayout.Space(10);
  101. GUILayout.BeginHorizontal();
  102. GUILayout.Label("References:", labelWidth);
  103. GUILayout.BeginVertical();
  104. DrawLinks(_selectedThing.references);
  105. GUILayout.EndVertical();
  106. GUILayout.EndHorizontal();
  107. }
  108. GUILayout.Space(10);
  109. GUILayout.Label("Referenced by:");
  110. DrawLinks(_selectedThing.referencedBy);
  111. GUILayout.Space(10);
  112. if (_shortestPath != null)
  113. {
  114. if (_shortestPath.Length > 1)
  115. {
  116. GUILayout.Label("ShortestPathToRoot");
  117. DrawLinks(_shortestPath);
  118. }
  119. string reason;
  120. _shortestPathToRootFinder.IsRoot(_shortestPath.Last(), out reason);
  121. GUILayout.Label("This is a root because:");
  122. GUILayout.TextArea(reason);
  123. }
  124. else
  125. {
  126. GUILayout.TextArea("No root is keeping this object alive. It will be collected next UnloadUnusedAssets() or scene load");
  127. }
  128. }
  129. GUILayout.EndScrollView();
  130. GUILayout.EndArea();
  131. }
  132. private void DrawSpecificTexture2D(NativeUnityEngineObject nativeObject)
  133. {
  134. if (nativeObject.className != "Texture2D")
  135. {
  136. _textureObject = null;
  137. return;
  138. }
  139. EditorGUILayout.HelpBox("Watching Texture Detail Data is only for Editor.", MessageType.Warning, true);
  140. if (_prevInstance != nativeObject.instanceID)
  141. {
  142. _textureObject = EditorUtility.InstanceIDToObject(nativeObject.instanceID) as Texture2D;
  143. _prevInstance = nativeObject.instanceID;
  144. }
  145. if (_textureObject != null)
  146. {
  147. EditorGUILayout.LabelField("textureInfo: " + _textureObject.width + "x" + _textureObject.height + " " + _textureObject.format);
  148. EditorGUILayout.ObjectField(_textureObject, typeof(Texture2D));
  149. _textureSize = EditorGUILayout.Slider(_textureSize, 100.0f, 1024.0f);
  150. GUILayout.Label(_textureObject, GUILayout.Width(_textureSize), GUILayout.Height(_textureSize * _textureObject.height / _textureObject.width));
  151. }
  152. else
  153. {
  154. EditorGUILayout.LabelField("Can't instance texture,maybe it was already released.");
  155. }
  156. }
  157. private void DrawArray(ManagedObject managedObject)
  158. {
  159. var typeDescription = managedObject.typeDescription;
  160. int elementCount = ArrayTools.ReadArrayLength(_unpackedCrawl.managedHeap, managedObject.address, typeDescription, _unpackedCrawl.virtualMachineInformation);
  161. GUILayout.Label("element count: " + elementCount);
  162. int rank = typeDescription.arrayRank;
  163. GUILayout.Label("arrayRank: " + rank);
  164. if (_unpackedCrawl.typeDescriptions[typeDescription.baseOrElementTypeIndex].isValueType)
  165. {
  166. GUILayout.Label("Cannot yet display elements of value type arrays");
  167. return;
  168. }
  169. if (rank != 1)
  170. {
  171. GUILayout.Label("Cannot display non rank=1 arrays yet.");
  172. return;
  173. }
  174. var pointers = new List<UInt64>();
  175. for (int i = 0; i != elementCount; i++)
  176. {
  177. pointers.Add(_primitiveValueReader.ReadPointer(managedObject.address + (UInt64)_unpackedCrawl.virtualMachineInformation.arrayHeaderSize + (UInt64)(i * _unpackedCrawl.virtualMachineInformation.pointerSize)));
  178. }
  179. GUILayout.Label("elements:");
  180. DrawLinks(pointers);
  181. }
  182. private void DrawFields(TypeDescription typeDescription, BytesAndOffset bytesAndOffset, bool useStatics = false)
  183. {
  184. int counter = 0;
  185. foreach (var field in TypeTools.AllFieldsOf(typeDescription, _unpackedCrawl.typeDescriptions, useStatics ? TypeTools.FieldFindOptions.OnlyStatic : TypeTools.FieldFindOptions.OnlyInstance))
  186. {
  187. counter++;
  188. var gUIStyle = counter % 2 == 0 ? Styles.entryEven : Styles.entryOdd;
  189. gUIStyle.margin = new RectOffset(0, 0, 0, 0);
  190. gUIStyle.overflow = new RectOffset(0, 0, 0, 0);
  191. gUIStyle.padding = EditorStyles.label.padding;
  192. GUILayout.BeginHorizontal(gUIStyle);
  193. GUILayout.Label(field.name, labelWidth);
  194. GUILayout.BeginVertical();
  195. DrawValueFor(field, bytesAndOffset.Add(field.offset));
  196. GUILayout.EndVertical();
  197. GUILayout.EndHorizontal();
  198. }
  199. }
  200. private void DrawFields(ManagedObject managedObject)
  201. {
  202. if (managedObject.typeDescription.isArray)
  203. return;
  204. GUILayout.Space(10);
  205. GUILayout.Label("Fields:");
  206. DrawFields(managedObject.typeDescription, _unpackedCrawl.managedHeap.Find(managedObject.address, _unpackedCrawl.virtualMachineInformation));
  207. }
  208. private void DrawValueFor(FieldDescription field, BytesAndOffset bytesAndOffset)
  209. {
  210. var typeDescription = _unpackedCrawl.typeDescriptions[field.typeIndex];
  211. switch (typeDescription.name)
  212. {
  213. case "System.Int32":
  214. GUILayout.Label(_primitiveValueReader.ReadInt32(bytesAndOffset).ToString());
  215. break;
  216. case "System.Int64":
  217. GUILayout.Label(_primitiveValueReader.ReadInt64(bytesAndOffset).ToString());
  218. break;
  219. case "System.UInt32":
  220. GUILayout.Label(_primitiveValueReader.ReadUInt32(bytesAndOffset).ToString());
  221. break;
  222. case "System.UInt64":
  223. GUILayout.Label(_primitiveValueReader.ReadUInt64(bytesAndOffset).ToString());
  224. break;
  225. case "System.Int16":
  226. GUILayout.Label(_primitiveValueReader.ReadInt16(bytesAndOffset).ToString());
  227. break;
  228. case "System.UInt16":
  229. GUILayout.Label(_primitiveValueReader.ReadUInt16(bytesAndOffset).ToString());
  230. break;
  231. case "System.Byte":
  232. GUILayout.Label(_primitiveValueReader.ReadByte(bytesAndOffset).ToString());
  233. break;
  234. case "System.SByte":
  235. GUILayout.Label(_primitiveValueReader.ReadSByte(bytesAndOffset).ToString());
  236. break;
  237. case "System.Char":
  238. GUILayout.Label(_primitiveValueReader.ReadChar(bytesAndOffset).ToString());
  239. break;
  240. case "System.Boolean":
  241. GUILayout.Label(_primitiveValueReader.ReadBool(bytesAndOffset).ToString());
  242. break;
  243. case "System.Single":
  244. GUILayout.Label(_primitiveValueReader.ReadSingle(bytesAndOffset).ToString());
  245. break;
  246. case "System.Double":
  247. GUILayout.Label(_primitiveValueReader.ReadDouble(bytesAndOffset).ToString());
  248. break;
  249. case "System.IntPtr":
  250. GUILayout.Label(_primitiveValueReader.ReadPointer(bytesAndOffset).ToString("X"));
  251. break;
  252. default:
  253. if (!typeDescription.isValueType)
  254. {
  255. ThingInMemory item = GetThingAt(bytesAndOffset.ReadPointer());
  256. if (item == null)
  257. {
  258. EditorGUI.BeginDisabledGroup(true);
  259. GUILayout.Button("Null");
  260. EditorGUI.EndDisabledGroup();
  261. }
  262. else
  263. {
  264. DrawLinks(new ThingInMemory[] { item });
  265. }
  266. }
  267. else
  268. {
  269. DrawFields(typeDescription, bytesAndOffset);
  270. }
  271. break;
  272. }
  273. }
  274. private ThingInMemory GetThingAt(ulong address)
  275. {
  276. if (!objectCache.ContainsKey(address))
  277. {
  278. objectCache[address] = _unpackedCrawl.allObjects.OfType<ManagedObject>().FirstOrDefault(mo => mo.address == address);
  279. }
  280. return objectCache[address];
  281. }
  282. /*
  283. private Item FindItemPointedToByManagedFieldAt(BytesAndOffset bytesAndOffset)
  284. {
  285. var stringAddress = _primitiveValueReader.ReadPointer(bytesAndOffset);
  286. return
  287. _items.FirstOrDefault(i =>
  288. {
  289. var m = i._thingInMemory as ManagedObject;
  290. if (m != null)
  291. {
  292. return m.address == stringAddress;
  293. }
  294. return false;
  295. });
  296. }*/
  297. private void DrawLinks(IEnumerable<UInt64> pointers)
  298. {
  299. DrawLinks(pointers.Select(p => GetThingAt(p)));
  300. }
  301. private void DrawLinks(IEnumerable<ThingInMemory> thingInMemories)
  302. {
  303. var c = GUI.backgroundColor;
  304. GUI.skin.button.alignment = TextAnchor.UpperLeft;
  305. foreach (var rb in thingInMemories)
  306. {
  307. EditorGUI.BeginDisabledGroup(rb == _selectedThing || rb == null);
  308. GUI.backgroundColor = ColorFor(rb);
  309. var caption = rb == null ? "null" : rb.caption;
  310. var managedObject = rb as ManagedObject;
  311. if (managedObject != null && managedObject.typeDescription.name == "System.String")
  312. caption = StringTools.ReadString(_unpackedCrawl.managedHeap.Find(managedObject.address, _unpackedCrawl.virtualMachineInformation), _unpackedCrawl.virtualMachineInformation);
  313. if (GUILayout.Button(caption))
  314. _hostWindow.SelectThing(rb);
  315. EditorGUI.EndDisabledGroup();
  316. }
  317. GUI.backgroundColor = c;
  318. }
  319. private Color ColorFor(ThingInMemory rb)
  320. {
  321. if (rb == null)
  322. return Color.gray;
  323. if (rb is NativeUnityEngineObject)
  324. return Color.red;
  325. if (rb is ManagedObject)
  326. return Color.Lerp(Color.blue, Color.white, 0.5f);
  327. if (rb is GCHandle)
  328. return Color.magenta;
  329. if (rb is StaticFields)
  330. return Color.yellow;
  331. throw new ArgumentException("Unexpected type: " + rb.GetType());
  332. }
  333. }
  334. }