Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable.
CloseFor some reason your suggested change could not be submitted. Please <a>try again</a> in a few minutes. And thank you for taking the time to help us improve the quality of Unity Documentation.
Closepath | Destination path for the memory snapshot file. |
finishCallback | Event that is fired once the memory snapshot has finished the process of capturing data. The first parameter denotes if a snapshot file was successfully created on the calling device, the second one contains the resulting snapshot path. |
screenshotCallback | Event that you can specify to retrieve a screenshot after the snapshot has finished. The first parameter denotes if a screenshot file was successfully created on the calling device, the second one contains the resulting screenshot path and the third one the data of the snapshot as DebugScreenCapture. |
captureFlags | Flag mask defining the content of the memory snapshot. |
Triggers a memory snapshot capture to generate a capture of the memory state that the Memory Profiler can open and analyze.
Request a memory snapshot capture with the provided arguments. Not all fields corresponding to the capture flags are collected. This depends on the target build used to capture the snapshot. Specifically CaptureFlags.NativeAllocationSites and CaptureFlags.NativeStackTraces relate to data that can only be collected from a build that supports the collection of native call stack information. Collecting native call stack information currently requires source code access. When providing these flags to capture from builds that do not support them they are ignored.
The path
parameter relates to the device that the call is made on, but the connection state of the Editor or Player this method is called from determines what process is captured and where the snapshot file will be created:
In the system, there are two different behaviors of data collection:
* When you call this from a Player that is connected to an Editor via PlayerConnection, the file is not stored locally but streamed out to the connected Editor. The provided path should be empty, or MemoryProfiler.TakeTempSnapshot could be called instead. The bool value of the finishCallback
will be false, even if the snapshot was succesfully saved in the Editor.
* When you call this from a Player that is not connected to an Editor via PlayerConnection, the file is created on the host device of the Player.
* When you call this from an Editor, the file is created on the host device of the Editor. If the Editor is not connected to a Player via EditorConnection, it will capture the Player, otherwise it will capture the Editor.
Metadata collection happens just before the snapshot is taken, if at least one listener was registered to the MemoryProfiler.CreatingMetadata event. At the end of the process, the finishCallback
is triggered. If a screenshot callback was provided to the call, this is called at the end of the current frame.
Note:
* If an absolute path is provided, make sure the application can write to that path. If only a file name or a relative path are provided, the snapshot will be stored at a path relative to Application.dataPath and API like File.Open can be used with the same relative path information.
* Listeners of the MemoryProfiler.CreatingMetadata event are notified in the Player or Editor that is being captured, which might not be the Editor that called this method but a connected Player instead.
* Screenshot callbacks are only called in standalone players or in Play mode. If no callbacks are supplied for screenshotCallback
, no screenshot is taken.
* It's recommended to call this API from within a Coroutine, yielding until both callbacks have been called, because the capture process locks code execution on the host device while it is taken and takes time to execute. Calling the API from a coroutine prevents the capturing Editor from locking up in the meantime.
* There is no way to capture Play mode in isolation, only the entire Editor. Memory usage in the Editor can differ drastically from that in a built Player. Always make sure to analyze memory usage in development Players running on your target devices.
* You can only take the next snapshot after the finishCallback
is triggered.
* Use the Memory Profiler package to open and analyze the resulting files.
using System; using System.Collections; using System.IO; using Unity.Collections.LowLevel.Unsafe; using Unity.Collections; using Unity.Profiling; using Unity.Profiling.Memory; using UnityEngine;
#if UNITY_EDITOR using UnityEditor; using UnityEditor.Networking.PlayerConnection; using UnityEngine.Networking.PlayerConnection; // Reguires com.unity.editorcoroutines package to be installed and its assembly referenced using Unity.EditorCoroutines.Editor; #endif
#if UNITY_EDITOR public class MemoryProfilerExampleWindow : EditorWindow { IConnectionState m_PlayerConnectionState; [MenuItem("Windows/Analysis/MemoryProfilerAPIExample")] static void InitializeOnLoad() { var window = EditorWindow.GetWindow<MemoryProfilerExampleWindow>(); window.m_PlayerConnectionState = PlayerConnectionGUIUtility.GetConnectionState(window); window.Show(); }
void TakeSnapshot() { // In the Unity Editor, the screenshot function only gets called when the not profiling Playmode or if Playmode is active. // In otherwords, capturing an Editor outside of Playmode does not create a screenshot and waiting for the callback would create and endless loop. var takeScreenshot = m_PlayerConnectionState.connectedToTarget == ConnectionTarget.Player || Application.isPlaying; EditorCoroutineUtility.StartCoroutine(MemoryProfilerExample.TakeSnapshot(takeScreenshot), this); } } #endif
public static class MemoryProfilerExample { public static IEnumerator TakeSnapshot(bool takeScreenshot) { var snapshotFileName = "SnapshotName.tmpsnap"; // Make sure the file does not exist, e.g. as a left over of a failed previous attempt to take a snapshot. if (File.Exists(snapshotFileName)) File.Delete(snapshotFileName);
var snapshotFinished = false; var screenshoFinished = false; string resultingSnapshotPath = null; string resultingScreenshotPath = null; var captureFlags = CaptureFlags.ManagedObjects | CaptureFlags.NativeObjects | CaptureFlags.NativeAllocations; Action<string, bool> snapshotCaptureFunction = (snapshotFilePath, success) => { snapshotFinished = true; if (success) { resultingSnapshotPath = Path.GetFullPath(snapshotFilePath); Debug.Log($"Snapshot captured and stored at {resultingSnapshotPath}."); } else { Debug.LogError("Failed to take a snapshot."); } }; Action<string, bool, DebugScreenCapture> screenshotCaptureFunction = (screenshotFilePath, success, screenshotData) => { screenshoFinished = true; if (!success || screenshotData.RawImageDataReference.Length == 0) return;
// Note: for the Memory Profiler to be able to pick up the screenshot, the name and path needs to match that of the snapshot file, safe for the extension. // The path provided by the callback is based on the path provided to TakeSnapshot. if (Path.HasExtension(screenshotFilePath)) { screenshotFilePath = Path.ChangeExtension(screenshotFilePath, ".tmppng"); }
var texture = new Texture2D(screenshotData.Width, screenshotData.Height, screenshotData.ImageFormat, false, false); CopyDataToTexture(texture, screenshotData.RawImageDataReference); File.WriteAllBytes(screenshotFilePath, texture.EncodeToPNG()); if (Application.isPlaying) UnityEngine.Object.Destroy(texture); else UnityEngine.Object.DestroyImmediate(texture); resultingScreenshotPath = screenshotFilePath; };
if (takeScreenshot) MemoryProfiler.TakeSnapshot(snapshotFileName, snapshotCaptureFunction, screenshotCaptureFunction, captureFlags); else MemoryProfiler.TakeSnapshot(snapshotFileName, snapshotCaptureFunction, captureFlags);
// The finishCallback is called first. while (!snapshotFinished) { yield return null; } // The screenshotCallback is called second and can take a moment longer, // but don't wait for it if it is not being taken. while (takeScreenshot && !screenshoFinished) { yield return null; }
if (resultingSnapshotPath != null && File.Exists(resultingSnapshotPath)) { var finalSnapshotPath = Path.ChangeExtension(resultingSnapshotPath, ".snap"); var finalScreenshotPath = resultingScreenshotPath != null ? Path.ChangeExtension(resultingScreenshotPath, ".png") : null;
// Remove any pre-existing files first. if (File.Exists(finalSnapshotPath)) File.Delete(finalSnapshotPath); if (finalScreenshotPath != null && File.Exists(finalScreenshotPath)) File.Delete(finalScreenshotPath);
// Now that writing to the file has succesfully completed, rename the file to the .snap extension to denote that the Memory Profiler can open it. File.Move(resultingSnapshotPath, finalSnapshotPath); if (finalScreenshotPath != null) File.Move(resultingScreenshotPath, finalScreenshotPath);
// If you don't have access to the Player's file system you could also upload the file to an end-point that is accessible to you here. } }
static void CopyDataToTexture(Texture2D tex, NativeArray<byte> byteArray) { unsafe { void* srcPtr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(byteArray); void* dstPtr = tex.GetRawTextureData<byte>().GetUnsafeReadOnlyPtr(); UnsafeUtility.MemCpy(dstPtr, srcPtr, byteArray.Length * sizeof(byte)); } } }
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.