Memory Profiler API

Use this forum for questions on how to use .NET Memory Profiler and how to analyse memory usage.
Post Reply
alexandrv
Posts: 3
Joined: Thu Jun 07, 2018 2:31 pm

Memory Profiler API

Post by alexandrv » Thu Jun 07, 2018 2:55 pm

Hi,

I'm trying to use Memory Profiler API to automate memory profiling process. I faced with several issues or limitations.

1. If I attach profiler to running process, API is not able to find objects. MemProfiler.IsProfiling() always returns false in this case.

2. If I start application from profiler, MemProfiler.IsProfiling() returns true, but it is able to find objects of given type only if I call API methods in the main thread. I use the code below to check if object of MyType exists in the memory.

MemProfiler.FastSnapshot();
MemAssertion.Assert(new AssertionsDefinition().NoInstances(typeof(MyType), true));

If this code is called in some other thread, it does not find any objects.

3. MemAssertion.Assert() always shows me window when condition in braces is false, but I don't need any UI, I just need the result of check.

Andreas Suurkuusk
Posts: 1000
Joined: Wed Mar 02, 2005 7:53 pm

Re: Memory Profiler API

Post by Andreas Suurkuusk » Thu Jun 07, 2018 8:36 pm

  1. Currently the .NET Memory Profiler API is not available when you attach to a process (the MemProfiler.IsProfiling property will return false as you noticed). When attaching to a process, the profiler will not get notifications about allocations and can therefore not provide information about the number of allocated instances and bytes. However, it is possible to add support for other parts of the profiler API, e.g. live instances information and assertions, and this is something we plan to do for the next version of the profiler.
  2. The MemAssertion.Assert overload you used will only check instances allocated by the calling thread. To check instances in all threads, you need to supply and additional argument: AssertionsThread.All. E.g. MemAssertion.Assert(new AssertionsDefinition().NoInstances(typeof(MyType), true), AssertionsThread.All); For more information, see the API reference documentation.
  3. You can change the default session settings so that the profiler will perform selected actions instead of showing a user interface window. You can access the default settings using Tools->Options and the select the "Memory leak" page. Here you can select the option "Perform actions".
    MemLeakActions.png
Best regards,

Andreas Suurkuusk
SciTech Software AB

alexandrv
Posts: 3
Joined: Thu Jun 07, 2018 2:31 pm

Re: Memory Profiler API

Post by alexandrv » Fri Jun 08, 2018 12:54 pm

Hi Andreas, thank you for detailed explanation.
Now the issues 2 and 3 are resolved (for #3 I used settings in the profiler project to avoid displaying window).

Now I have more questions.

- is that possible using API to get the process ID of the process that was started by profiler? Now I run profiler from command line and pass the application name to start. Then I find the application process by name, that does not seem reliable way.

- is there a difference what utility to use to start profiling from command line - NetMemProfiler (with /noui flag), NetMemProfilerConsole or NmpCore?

- I found that some my objects are left in the memory if I do memory profiling using API. If I do similar memory profiling manually the results are different. I have not investigated it yet, probably you have some advises. Particularly, does it do garbage collection when I call MemProfiler.FastSnapshot()?

Andreas Suurkuusk
Posts: 1000
Joined: Wed Mar 02, 2005 7:53 pm

Re: Memory Profiler API

Post by Andreas Suurkuusk » Mon Jun 11, 2018 12:31 pm

What process id are you looking for? The API is used within the profiled process, so the process id of this process can be retrieved using Process.GetCurrentProcess().Id. Are you profiling multiple processes?

There are some minor differences between NmpCore and NetMemProfiler(Console),e..g. WPF clean-up is currently not performed by NmpCore. NetMemProfilerConsole was created before NmpCore, but now we recommend that you use NmpCore for automated memory tests, unless you want to be able to show a user interface.

When using the API, the profiler will not perform as extensive garbage collection as it does when collecting a snapshot in the user interface. In particular, the MemProfiler.FastSnapshot method will only perform a single gen #0 collection.If you want to make sure that all instances are full collected before performing assertions, you can use the following code:

Code: Select all

GC.Collect();
GC.WaitForPendingFinalizers();

// Perform assertions (assertions will trigger a single full garbage collection)
(MemProfiler.FullSnapshot is equivalent to collecting a snapshot in the user interface)
Best regards,

Andreas Suurkuusk
SciTech Software AB

alexandrv
Posts: 3
Joined: Thu Jun 07, 2018 2:31 pm

Re: Memory Profiler API

Post by alexandrv » Mon Jun 11, 2018 1:34 pm

Thank you for answers.

I'm looking for the ID of the profiled process and I need to somehow get to know it outside the profiled process.
Below is the simplified version of my code to start NmpCore:

new Process { StartInfo = { FileName = "NmpCore", Arguments = "/prj " + memProfilerPrjPath + " /cp-"} }.Start();

Thread.Sleep(10000);

Process myApplicationProcess = Process.GetProcessesByName(GetExeName())[0];

then the UI tests uses this myApplicationProcess reference to control the application.

I'd like to avoid finding application process by name.



You mentioned that "WPF clean-up is currently not performed by NmpCore." My application uses WPF. Does it mean it is more suitable to use NetMemProfilerConsole for it?

Andreas Suurkuusk
Posts: 1000
Joined: Wed Mar 02, 2005 7:53 pm

Re: Memory Profiler API

Post by Andreas Suurkuusk » Tue Jun 12, 2018 11:52 am

It is not possible to retrieve the process id when starting the profiler as a separate process, but another option is to use the external profiler API to start the profiled process. Unfortunately, this API is the same API as the profiler itself uses and it may not be stable between versions. In particular, it may be significantly modified for the 6.0 release. It also lacks public documentation.

Below you will find a test program that shows how you can start profiling using the external API. In order to compile this you need to add a project reference to SciTech.NetMemProfiler.Core, which you can find under the "Assemblies" directory in the profiler installation directory.

The test program also requires the full memory profiler to be installed on the machine.

Code: Select all

using SciTech.Profiler;
using System;
using System.Threading;

internal class Program
{
    private static void Main(string[] args)
    {
        var app = new ProfilerApplicationCore();

        var project = app.LoadProject(@"<path>");

        using (var session = app.CreateSession(project))
        {
            // You can override the process to start (as specified by the project) by 
            // assigning StartProcesses.
            var startInfo = new ProfileProcessStartInfo(ProfilingType.Application, @"<path>");
            startInfo.AllowedProcesses = AllowedProcess.OnlyStarted;

            session.StartProcesses = new ProfileProcessStartInfo[] { startInfo };

            // Create an event that will signal that the profiled process has exited.
            using (ManualResetEvent stoppedEvent = new ManualResetEvent(false))
            {
                // Signal stopped event when session has stopped.
                session.StateChanged += (o, e) =>
                {
                    if (session.State == ActiveSessionState.Stopped) stoppedEvent.Set();
                };

                // Start the profiling.
                session.Start(TimeSpan.FromMinutes(1));

                var processes = session.GetProfiledProcesses();
                if (processes.Length > 0)
                {
                    Console.WriteLine($"Process id: {processes[0].Header.OsPid}");
                }
                else
                {
                    Console.WriteLine("Error, no process is being profiled");
                }

                // Wait for the profiled process to exit (alternatively call session.Stop to 
                // terminate the process)
                stoppedEvent.WaitOne();
            }
        }

    }
}
More examples on how to use the API can be found in the following forum posts:

viewtopic.php?f=2&t=4421
viewtopic.php?f=2&t=4299
viewtopic.php?f=2&t=3888
viewtopic.php?f=2&t=1435
viewtopic.php?f=3&t=1317


WPF uses weak references for weak events and some bindings. It will periodically clean-up left over weak references (and related events/bindings), but when collecting profiler snapshots there may still be a pending clean-up. Therefore the profiler tries to trigger this clean-up when collecting a snapshot, but this will not occur when using NmpCore.
Best regards,

Andreas Suurkuusk
SciTech Software AB

Post Reply

Who is online

Users browsing this forum: No registered users and 6 guests