void OnHeapReceivedSaveOnly(UnityEditor.MemoryProfiler.PackedMemorySnapshot snapshot) { UnityEditor.MemoryProfiler.MemorySnapshot.OnSnapshotReceived -= OnHeapReceivedSaveOnly; EditorUtility.DisplayProgressBar(HeGlobals.k_Title, "Saving memory...", 0.5f); try { var args = new MemorySnapshotProcessingArgs(); args.source = snapshot; args.excludeNativeFromConnections = excludeNativeFromConnections; var heap = PackedMemorySnapshot.FromMemoryProfiler(args); heap.SaveToFile(autoSavePath); HeMruFiles.AddPath(autoSavePath); ShowNotification(new GUIContent(string.Format("Memory snapshot saved as\n'{0}'", autoSavePath))); } catch { m_CloseDueToError = true; throw; } finally { m_IsCapturing = false; m_Repaint = true; EditorUtility.ClearProgressBar(); } }
void OnHeapReceived(UnityEditor.MemoryProfiler.PackedMemorySnapshot snapshot) { UnityEditor.MemoryProfiler.MemorySnapshot.OnSnapshotReceived -= OnHeapReceived; EditorUtility.DisplayProgressBar(HeGlobals.k_Title, "Reading memory...", 0.5f); try { m_Heap = null; if (useThreads) { var job = new ReceiveThreadJob { threadFunc = ReceiveHeapThreaded, snapshot = snapshot }; ScheduleJob(job); } else { EditorUtility.DisplayProgressBar(HeGlobals.k_Title, "Analyzing memory...", 0.75f); ReceiveHeapThreaded(snapshot); } } finally { snapshotPath = string.Format("Captured Snapshot at {0}", DateTime.Now.ToShortTimeString()); m_IsCapturing = false; m_Repaint = true; EditorUtility.ClearProgressBar(); } }
void OnSnapshotReceived(UnityEditor.MemoryProfiler.PackedMemorySnapshot snapshot) { UnityEditor.MemoryProfiler.MemorySnapshot.OnSnapshotReceived -= OnSnapshotReceived; var args = new MemorySnapshotProcessingArgs(); args.source = snapshot; args.excludeNativeFromConnections = false; m_snapshot = PackedMemorySnapshot.FromMemoryProfiler(args); }
static void VerifyMemoryProfilerSnapshot(UnityEditor.MemoryProfiler.PackedMemorySnapshot snapshot) { if (snapshot == null) { throw new Exception("No snapshot was found."); } if (snapshot.typeDescriptions == null || snapshot.typeDescriptions.Length == 0) { throw new Exception("The snapshot does not contain any 'typeDescriptions'. This is a known issue when using .NET 4.x Scripting Runtime.\n(Case 1079363) PackedMemorySnapshot: .NET 4.x Scripting Runtime breaks memory snapshot"); } if (snapshot.managedHeapSections == null || snapshot.managedHeapSections.Length == 0) { throw new Exception("The snapshot does not contain any 'managedHeapSections'. This is a known issue when using .NET 4.x Scripting Runtime.\n(Case 1079363) PackedMemorySnapshot: .NET 4.x Scripting Runtime breaks memory snapshot"); } if (snapshot.gcHandles == null || snapshot.gcHandles.Length == 0) { throw new Exception("The snapshot does not contain any 'gcHandles'. This is a known issue when using .NET 4.x Scripting Runtime.\n(Case 1079363) PackedMemorySnapshot: .NET 4.x Scripting Runtime breaks memory snapshot"); } if (snapshot.nativeTypes == null || snapshot.nativeTypes.Length == 0) { throw new Exception("The snapshot does not contain any 'nativeTypes'."); } if (snapshot.nativeObjects == null || snapshot.nativeObjects.Length == 0) { throw new Exception("The snapshot does not contain any 'nativeObjects'."); } if (snapshot.connections == null || snapshot.connections.Length == 0) { throw new Exception("The snapshot does not contain any 'connections'."); } }
public static bool Convert(UnityEditor.MemoryProfiler.PackedMemorySnapshot snapshot, string writePath) { MemorySnapshotFileWriter writer = null; try { writer = new MemorySnapshotFileWriter(writePath); } catch (Exception e) { Debug.LogError("Failed to create snapshot file: " + e.Message); return(false); } //snapshot version will always be the remap connections version as that is the last change affecting this format writer.WriteEntry(EntryType.Metadata_Version, (uint)FormatHistory.NativeConnectionsAsInstanceIdsVersion); //timestamp with conversion date writer.WriteEntry(EntryType.Metadata_RecordDate, (ulong)DateTime.Now.Ticks); //prepare metadata string platform = "Unknown"; string content = "Converted Snapshot"; int stringDataLength = (platform.Length + content.Length) * sizeof(char); byte[] metaDataBytes = new byte[stringDataLength + (sizeof(int) * 3)]; // add space for serializing the lengths of the strings int offset = 0; offset = ExperimentalMemoryProfiler.WriteIntToByteArray(metaDataBytes, offset, content.Length); offset = ExperimentalMemoryProfiler.WriteStringToByteArray(metaDataBytes, offset, content); offset = ExperimentalMemoryProfiler.WriteIntToByteArray(metaDataBytes, offset, platform.Length); offset = ExperimentalMemoryProfiler.WriteStringToByteArray(metaDataBytes, offset, platform); offset = ExperimentalMemoryProfiler.WriteIntToByteArray(metaDataBytes, offset, 0); // Write metadata writer.WriteEntryArray(EntryType.Metadata_UserMetadata, metaDataBytes); writer.WriteEntry(EntryType.Metadata_CaptureFlags, (UInt32)CaptureFlags.ManagedObjects); //capture just managed // Write managed heap sections for (int i = 0; i < snapshot.managedHeapSections.Length; ++i) { var heapSection = snapshot.managedHeapSections[i]; writer.WriteEntry(EntryType.ManagedHeapSections_StartAddress, heapSection.m_StartAddress); writer.WriteEntryArray(EntryType.ManagedHeapSections_Bytes, heapSection.m_Bytes); } // Write managed types int fieldDescriptionCount = 0; for (int i = 0; i < snapshot.typeDescriptions.Length; ++i) { var type = snapshot.typeDescriptions[i]; writer.WriteEntry(EntryType.TypeDescriptions_Flags, (UInt32)type.m_Flags); writer.WriteEntry(EntryType.TypeDescriptions_BaseOrElementTypeIndex, type.baseOrElementTypeIndex); writer.WriteEntry(EntryType.TypeDescriptions_TypeIndex, type.typeIndex); if (!type.isArray) { var typeFields = type.fields; int[] fieldIndices = new int[typeFields.Length]; for (int j = 0; j < typeFields.Length; ++j) { var field = typeFields[j]; fieldIndices[j] = fieldDescriptionCount; ++fieldDescriptionCount; writer.WriteEntry(EntryType.FieldDescriptions_Offset, field.offset); writer.WriteEntry(EntryType.FieldDescriptions_TypeIndex, field.typeIndex); writer.WriteEntry(EntryType.FieldDescriptions_Name, field.name); writer.WriteEntry(EntryType.FieldDescriptions_IsStatic, field.isStatic); } writer.WriteEntryArray(EntryType.TypeDescriptions_FieldIndices, fieldIndices); writer.WriteEntryArray(EntryType.TypeDescriptions_StaticFieldBytes, type.staticFieldBytes); } else { writer.WriteEntryArray(EntryType.TypeDescriptions_FieldIndices, new int[0]); writer.WriteEntryArray(EntryType.TypeDescriptions_StaticFieldBytes, new byte[0]); } writer.WriteEntry(EntryType.TypeDescriptions_Name, type.name); writer.WriteEntry(EntryType.TypeDescriptions_Assembly, type.assembly); writer.WriteEntry(EntryType.TypeDescriptions_TypeInfoAddress, type.typeInfoAddress); writer.WriteEntry(EntryType.TypeDescriptions_Size, type.size); } //write managed gc handles for (int i = 0; i < snapshot.gcHandles.Length; ++i) { var handle = snapshot.gcHandles[i]; writer.WriteEntry(EntryType.GCHandles_Target, handle.target); } //write managed connections for (int i = 0; i < snapshot.connections.Length; ++i) { var connection = snapshot.connections[i]; writer.WriteEntry(EntryType.Connections_From, connection.from); writer.WriteEntry(EntryType.Connections_To, connection.to); } //write native types for (int i = 0; i < snapshot.nativeTypes.Length; ++i) { var nativeType = snapshot.nativeTypes[i]; writer.WriteEntry(EntryType.NativeTypes_NativeBaseTypeArrayIndex, nativeType.nativeBaseTypeArrayIndex); writer.WriteEntry(EntryType.NativeTypes_Name, nativeType.name); } //write stub root reference for all native objects to point to, as the old format did not capture these writer.WriteEntry(EntryType.NativeRootReferences_AreaName, "Invalid Root"); writer.WriteEntry(EntryType.NativeRootReferences_AccumulatedSize, (ulong)0); writer.WriteEntry(EntryType.NativeRootReferences_Id, (long)0); writer.WriteEntry(EntryType.NativeRootReferences_ObjectName, "Invalid Root Object"); //write native objects for (int i = 0; i < snapshot.nativeObjects.Length; ++i) { var nativeObject = snapshot.nativeObjects[i]; writer.WriteEntry(EntryType.NativeObjects_Name, nativeObject.name); writer.WriteEntry(EntryType.NativeObjects_InstanceId, nativeObject.instanceId); writer.WriteEntry(EntryType.NativeObjects_Size, (ulong)nativeObject.size); writer.WriteEntry(EntryType.NativeObjects_NativeTypeArrayIndex, nativeObject.nativeTypeArrayIndex); writer.WriteEntry(EntryType.NativeObjects_HideFlags, (UInt32)nativeObject.hideFlags); writer.WriteEntry(EntryType.NativeObjects_Flags, (UInt32)nativeObject.m_Flags); writer.WriteEntry(EntryType.NativeObjects_NativeObjectAddress, (ulong)nativeObject.nativeObjectAddress); writer.WriteEntry(EntryType.NativeObjects_RootReferenceId, (long)0); } //write virtual machine information writer.WriteEntry(EntryType.Metadata_VirtualMachineInformation, snapshot.virtualMachineInformation); writer.Close(); return(true); }
// this method is a hack that excludes native object connections to workaround an unity bug. // https://forum.unity.com/threads/wip-heap-explorer-memory-profiler-debugger-and-analyzer-for-unity.527949/page-2#post-3615223 static PackedConnection[] ConnectionsFromMemoryProfilerWithoutNativeHACK(PackedMemorySnapshot snapshot, UnityEditor.MemoryProfiler.PackedMemorySnapshot source) { var managedStart = 0; var managedEnd = managedStart + source.gcHandles.Length; var nativeStart = managedStart + managedEnd; var nativeEnd = nativeStart + source.nativeObjects.Length; var output = new List <PackedConnection>(1024 * 1024); for (int n = 0, nend = source.connections.Length; n < nend; ++n) { if ((n % (nend / 100)) == 0) { var progress = ((n + 1.0f) / nend) * 100; snapshot.busyString = string.Format("Analyzing GCHandle Connections\n{0}/{1}, {2:F0}% done", n + 1, source.connections.Length, progress); } var connection = new PackedConnection { from = source.connections[n].from, to = source.connections[n].to, }; connection.fromKind = PackedConnection.Kind.GCHandle; if (connection.from >= nativeStart && connection.from < nativeEnd) { connection.from -= nativeStart; connection.fromKind = PackedConnection.Kind.Native; } connection.toKind = PackedConnection.Kind.GCHandle; if (connection.to >= nativeStart && connection.to < nativeEnd) { connection.to -= nativeStart; connection.toKind = PackedConnection.Kind.Native; } if (connection.fromKind != PackedConnection.Kind.Native) { output.Add(connection); } } snapshot.header.nativeObjectFromConnectionsExcluded = true; Debug.LogWarning("HeapExplorer: Native object 'from' connections are excluded due workaround an Unity bug. Thus the object connections in Heap Explorer show fewer connections than actually exist.\nhttps://forum.unity.com/threads/wip-heap-explorer-memory-profiler-debugger-and-analyzer-for-unity.527949/page-2#post-3615223"); return(output.ToArray()); }