Skip to content
8 changes: 8 additions & 0 deletions .openpublishing.redirection.core.json
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,14 @@
"source_path_from_root": "/docs/core/diagnostics/built-in-metrics-aspnetcore.md",
"redirect_url": "/aspnet/core/log-mon/metrics/built-in"
},
{
"source_path_from_root": "/docs/core/diagnostics/dotnet-trace-collect-linux-scenarios.md",
"redirect_url": "/dotnet/core/diagnostics/dotnet-trace-collect-linux-performance"
},
{
"source_path_from_root": "/docs/core/diagnostics/performance-diagnostics.md",
"redirect_url": "/dotnet/core/diagnostics/index#performance-tutorials"
},
{
"source_path_from_root": "/docs/core/docker/build-docker-netcore-container.md",
"redirect_url": "/dotnet/core/docker/build-container"
Expand Down Expand Up @@ -1388,15 +1396,15 @@
},
{
"source_path_from_root": "/docs/core/porting/how-to-upgrade-with-github-copilot.md",
"redirect_url": "/dotnet/core/porting/github-copilot-upgrade/how-to-upgrade-with-github-copilot"

Check failure on line 1399 in .openpublishing.redirection.core.json

View workflow job for this annotation

GitHub Actions / MSDocs build verifier

Redirect target returns 404: '/dotnet/core/porting/github-copilot-upgrade/dotnet-how-to-custom-upgrade-instructions'.
},
{
"source_path_from_root": "/docs/core/porting/libraries.md",
"redirect_url": "/dotnet/core/porting/"

Check failure on line 1403 in .openpublishing.redirection.core.json

View workflow job for this annotation

GitHub Actions / MSDocs build verifier

Redirect target returns 404: '/dotnet/core/porting/github-copilot-upgrade/dotnet-how-to-upgrade-with-github-copilot'.
},
{
"source_path_from_root": "/docs/core/porting/nuget-packages.md",
"redirect_url": "/dotnet/core/deploying"

Check failure on line 1407 in .openpublishing.redirection.core.json

View workflow job for this annotation

GitHub Actions / MSDocs build verifier

Redirect target returns 404: '/dotnet/core/porting/github-copilot-upgrade/dotnet-scenarios-and-skills'.
},
{
"source_path_from_root": "/docs/core/porting/tools.md",
Expand Down
29 changes: 15 additions & 14 deletions docs/core/diagnostics/debug-deadlock.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
---
title: Debugging deadlock - .NET Core
description: A tutorial that walks you through debugging a locking issue in .NET Core.
title: Debugging deadlock - .NET
description: A tutorial that walks you through debugging a locking issue in .NET.
ms.topic: tutorial
ms.date: 07/20/2020
ms.date: 09/08/2026
ai-usage: ai-assisted
---

# Debug a deadlock in .NET Core
# Debug a deadlock in .NET

**This article applies to: ✔️** .NET Core 3.1 SDK and later versions

In this tutorial, you'll learn how to debug a deadlock scenario. Using the provided example [ASP.NET Core web app](/samples/dotnet/samples/diagnostic-scenarios) source code repository, you can cause a deadlock intentionally. The endpoint will stop responding and experience thread accumulation. You'll learn how you can use various tools to analyze the problem, such as core dumps, core dump analysis, and process tracing.
In this tutorial, you'll learn how to debug a deadlock scenario. Using the provided example [ASP.NET Core web app](/samples/dotnet/samples/diagnostic-scenarios), you can cause a deadlock intentionally. The endpoint will stop responding and experience thread accumulation. You'll learn how to collect and analyze a process dump to identify the blocked threads, lock owners, and wait cycle.

In this tutorial, you will:

Expand All @@ -25,10 +24,9 @@ In this tutorial, you will:

The tutorial uses:

- [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet) or a later version
- A supported [.NET SDK](https://dotnet.microsoft.com/download/dotnet)
- [Sample debug target - web app](/samples/dotnet/samples/diagnostic-scenarios) to trigger the scenario
- [dotnet-trace](dotnet-trace.md) to list processes
- [dotnet-dump](dotnet-dump.md) to collect, and analyze a dump file
- [dotnet-dump](dotnet-dump.md) to list processes and collect and analyze a dump file

## Core dump generation

Expand All @@ -41,14 +39,18 @@ dotnet run
To find the process ID, use the following command:

```dotnetcli
dotnet-trace ps
dotnet-dump ps
```

Take note of the process ID from your command output. Our process ID was `4807`, but yours will be different. Navigate to the following URL, which is an API endpoint on the sample site:

`https://localhost:5001/api/diagscenario/deadlock`

The API request to the site will stop responding. Let the request run for about 10-15 seconds. Then create the core dump using the following command:
The API request to the site will stop responding. Let the request run for about 10-15 seconds.

A dump is the recommended artifact for an existing deadlock because it preserves the current threads, lock owners, and wait cycle.

Create the core dump using the following command:

### [Linux](#tab/linux)

Expand Down Expand Up @@ -259,12 +261,11 @@ The second thread is similar. It's also trying to acquire a lock that it already

## See also

- [dotnet-trace](dotnet-trace.md) to list processes
- [dotnet-counters](dotnet-counters.md) to check managed memory usage
- [dotnet-dump](dotnet-dump.md) to collect and analyze a dump file
- [dotnet/diagnostics](https://github.com/dotnet/diagnostics/tree/main/documentation/tutorial)

## Next steps

> [!div class="nextstepaction"]
> [What diagnostic tools are available in .NET Core](index.md)
> [What diagnostic tools are available in .NET](index.md)
51 changes: 30 additions & 21 deletions docs/core/diagnostics/debug-highcpu.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
---
title: Debug high CPU usage - .NET Core
description: A tutorial that walks you through debugging high CPU usage in .NET Core.
title: Debug high CPU usage - .NET
description: A tutorial that walks you through debugging high CPU usage in .NET.
ms.topic: tutorial
ms.date: 03/19/2026
ms.date: 09/08/2026
ai-usage: ai-assisted
---

# Debug high CPU usage in .NET Core
# Debug high CPU usage in .NET

**This article applies to: ✔️** .NET Core 3.1 SDK and later versions

In this tutorial, you'll learn how to debug an excessive CPU usage scenario. Using the provided example [ASP.NET Core web app](/samples/dotnet/samples/diagnostic-scenarios) source code repository, you can cause a deadlock intentionally. The endpoint will stop responding and experience thread accumulation. You'll learn how you can use various tools to diagnose this scenario with several key pieces of diagnostics data.
In this tutorial, you'll learn how to debug an excessive CPU usage scenario. Using the provided example [ASP.NET Core web app](/samples/dotnet/samples/diagnostic-scenarios), you can intentionally run CPU-intensive work and use metrics and platform-appropriate profiling tools to identify the expensive code.

In this tutorial, you will:

Expand All @@ -18,16 +17,16 @@ In this tutorial, you will:
> - Investigate high CPU usage
> - Determine CPU usage with [dotnet-counters](dotnet-counters.md)
> - Use [dotnet-trace](dotnet-trace.md) for trace generation
> - Profile performance in PerfView
> - Profile performance in Visual Studio or PerfView
> - Diagnose and solve excessive CPU usage

## Prerequisites

The tutorial uses:

- [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet) or a later version.
- A supported [.NET SDK](https://dotnet.microsoft.com/download/dotnet).
- [Sample debug target](/samples/dotnet/samples/diagnostic-scenarios) to trigger the scenario.
- [dotnet-trace](dotnet-trace.md) to list processes and generate a profile.
- [dotnet-trace](dotnet-trace.md) to collect CPU profiles and runtime traces.
- [dotnet-counters](dotnet-counters.md) to monitor cpu usage.

## CPU counters
Expand Down Expand Up @@ -171,15 +170,17 @@ Throughout the duration of the request, the CPU usage will hover around the incr

At this point, you can safely say the CPU is running higher than you expect. Identifying the effects of a problem is key to finding the cause. We will use the effect of high CPU consumption in addition to diagnostic tools to find the cause of the problem.

## Analyze High CPU with Profiler
## Analyze high CPU with a profiler

When analyzing an app with high CPU usage, use a profiler to understand what the code is doing. `dotnet-trace collect` works on all operating systems, but safe-point bias and managed-only callstacks limit it to more general information than a kernel-aware profiler like ETW for Windows or `perf` for Linux. Depending on your operating system and .NET version, improved profiling capabilities might be available—see the platform-specific tabs that follow for detailed guidance.
When analyzing an app with high CPU usage, use a profiler to understand what the code is doing. `dotnet-trace collect` works on all operating systems, but safe-point bias and managed-only call stacks limit it to more general information than kernel-aware profiling through ETW on Windows or `perf_events` on Linux. Depending on your operating system and .NET version, improved profiling capabilities might be available. See the platform-specific tabs that follow for detailed guidance.

### [Linux](#tab/linux)

For .NET 10 and later versions, use `dotnet-trace collect-linux`. If `collect-linux` isn't available, use `perf` for kernel-level CPU sampling. Also use `perf` when you need `perf.data`, perf-native analysis, or hardware performance counters.

#### Use `dotnet-trace collect-linux` (.NET 10+)

On .NET 10 and later, [`dotnet-trace collect-linux`](dotnet-trace.md#dotnet-trace-collect-linux) is the recommended profiling approach on Linux. It combines EventPipe with OS-level perf_events to produce a single unified trace that includes both managed and native callstacks, all without requiring a process restart. This requires root permissions and Linux kernel 6.4+ with `CONFIG_USER_EVENTS=y`. See [collect-linux prerequisites](dotnet-trace.md#prerequisites) for full requirements.
On .NET 10+, [`dotnet-trace collect-linux`](dotnet-trace.md#dotnet-trace-collect-linux) is the recommended Linux workflow. It retains .NET runtime and application event collection while adding kernel CPU samples, native call stacks, and selected Linux events through `perf_events`, all without requiring a process restart. This requires root permissions and Linux kernel 6.4+ with `CONFIG_USER_EVENTS=y`. See [collect-linux prerequisites](dotnet-trace.md#prerequisites) for full requirements.

Ensure the [sample debug target](/samples/dotnet/samples/diagnostic-scenarios) is configured to target .NET 10 or later, then run it and exercise the high CPU endpoint (`https://localhost:5001/api/diagscenario/highcpu/60000`) again. While it's running within the 1-minute request, run `dotnet-trace collect-linux` to capture a machine-wide trace:

Expand All @@ -189,13 +190,17 @@ sudo dotnet-trace collect-linux

Let it run for about 20-30 seconds, then press <kbd>Ctrl+C</kbd> or <kbd>Enter</kbd> to stop the collection. The result is a `.nettrace` file that includes both managed and native callstacks.

Open the `.nettrace` with [`PerfView`](https://github.com/microsoft/perfview/blob/main/documentation/Downloading.md) and use the **CPU Stacks** view to identify the methods consuming the most CPU time.
Copy the `.nettrace` file to a Windows machine. Use [Visual Studio](#analyze-high-cpu-data-with-visual-studio) for the managed CPU investigation.

PerfView provides an alternative CPU stack workflow and Linux-native symbol lookup.

For information about resolving native runtime symbols in the trace, see [Get symbols for native runtime frames](dotnet-trace.md#get-symbols-for-native-runtime-frames).
PerfView 3.2.1 or later can resolve .NET native and R2R symbols at analysis time. In PerfView, select unresolved module frames and choose **Lookup Symbols**. For other native libraries, configure a local symbol path. For more information, see [Get symbols for native runtime frames](dotnet-trace.md#get-symbols-for-native-runtime-frames).

For a worked diagnosis, see [Find a managed CPU hotspot](dotnet-trace-collect-linux-performance.md#example-find-a-managed-cpu-hotspot).

#### Use `perf`

The `perf` tool can also be used to generate .NET Core app profiles. Exit the previous instance of the [sample debug target](/samples/dotnet/samples/diagnostic-scenarios).
Use `perf` when `collect-linux` isn't available and you need kernel-level CPU sampling. Use `perf` directly when the investigation requires the Linux perf ecosystem, such as `perf.data`, `perf report`, `perf annotate`, established flame graph scripts, or hardware performance counters. The following steps demonstrate the standard `perf record` and `perf report` workflow. Exit the previous instance of the [sample debug target](/samples/dotnet/samples/diagnostic-scenarios).

Set the `DOTNET_PerfMapEnabled` environment variable to cause the .NET app to create a `map` file in the `/tmp` directory. This `map` file is used by `perf` to map CPU addresses to JIT-generated functions by name. For more information, see [Export perf maps and jit dumps](../runtime-config/debugging-profiling.md#export-perf-maps-and-jit-dumps).

Expand Down Expand Up @@ -239,24 +244,28 @@ dotnet-trace collect -p 22884 --providers Microsoft-DotNETCore-SampleProfiler

Let [dotnet-trace](dotnet-trace.md) run for about 20-30 seconds, and then press the <kbd>Enter</kbd> to exit the collection. The result is a `nettrace` file located in the same folder. The `nettrace` files are a great way to use existing analysis tools on Windows.

Open the `nettrace` with [`PerfView`](https://github.com/microsoft/perfview/blob/main/documentation/Downloading.md) by navigating to samples/core/diagnostics/DiagnosticScenarios/ and clicking on the arrow by the `nettrace` file. Open the 'Thread Time (with StartStop Activities) Stacks' and choose the 'CallTree' tab near the top. After checking the box to the left of one of the threads, your file should look similar to the one pictured below.
Start with [Visual Studio](#analyze-high-cpu-data-with-visual-studio) to inspect CPU use and follow the expensive call path.

Alternatively, open the `nettrace` with [`PerfView`](https://github.com/microsoft/perfview/blob/main/documentation/Downloading.md) by navigating to samples/core/diagnostics/DiagnosticScenarios/ and clicking on the arrow by the `nettrace` file. Open the 'Thread Time (with StartStop Activities) Stacks' and choose the 'CallTree' tab near the top. After checking the box to the left of one of the threads, your file should look similar to the one pictured below.

[![PerfView image](media/perfview.jpg)](media/perfview.jpg#lightbox)

---

## Analyzing High CPU Data with Visual Studio
## Analyze high CPU data with Visual Studio

In Visual Studio on Windows, select **File** > **Open** > **File** and open the `.nettrace` file. Select **CPU Usage**, then **Open details**. Use **Current View** to select **Functions** and compare **Self CPU** with **Total CPU**, which includes callees. Use **Caller/Callee** and **Call Tree** to follow the expensive application path.

All \*.nettrace files can be analyzed in Visual Studio. To analyze a Linux \*.nettrace file in Visual Studio, transfer the \*.nettrace file, in addition to the other necessary documents, to a Windows machine, and then open the \*.nettrace file in Visual Studio. For more information, see [Analyze CPU Usage Data](/visualstudio/profiling/beginners-guide-to-performance-profiling?#step-2-analyze-cpu-usage-data).
For more information, see [Analyze CPU Usage Data](/visualstudio/profiling/beginners-guide-to-performance-profiling?#step-2-analyze-cpu-usage-data).

## See also

- [dotnet-trace](dotnet-trace.md) to list processes
- [dotnet-trace](dotnet-trace.md) to collect CPU profiles and runtime traces
- [dotnet-counters](dotnet-counters.md) to check managed memory usage
- [dotnet-dump](dotnet-dump.md) to collect and analyze a dump file
- [dotnet/diagnostics](https://github.com/dotnet/diagnostics/tree/main/documentation/tutorial)

## Next steps

> [!div class="nextstepaction"]
> [Debug a deadlock in .NET Core](debug-deadlock.md)
> [Debug a deadlock in .NET](debug-deadlock.md)
11 changes: 5 additions & 6 deletions docs/core/diagnostics/debug-memory-leak.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
title: Debug a memory leak tutorial
description: Learn how to debug a memory leak in .NET.
ms.topic: tutorial
ms.date: 11/13/2023
ms.date: 09/08/2026
ai-usage: ai-assisted
---

# Debug a memory leak in .NET

**This article applies to:** ✔️ .NET Core 3.1 SDK and later versions

Memory can leak when your app references objects that it no longer needs to perform the desired task. Referencing these objects prevents the garbage collector from reclaiming the memory used. That can result in performance degradation and an <xref:System.OutOfMemoryException> exception being thrown.

This tutorial demonstrates the tools to analyze a memory leak in a .NET app using the .NET diagnostics CLI tools. If you're on Windows, you may be able to [use Visual Studio's Memory Diagnostic tools](/visualstudio/profiling/memory-usage) to debug the memory leak.
Expand All @@ -27,7 +26,7 @@ In this tutorial, you will:

The tutorial uses:

- [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet) or a later version.
- A supported [.NET SDK](https://dotnet.microsoft.com/download/dotnet).
- [dotnet-counters](dotnet-counters.md) to check managed memory usage.
- [dotnet-dump](dotnet-dump.md) to collect and analyze a dump file (includes the [SOS debugging extension](sos-debugging-extension.md)).
- A [sample debug target](/samples/dotnet/samples/diagnostic-scenarios/) app to diagnose.
Expand Down Expand Up @@ -266,7 +265,7 @@ You can also delete the dump file that was created.

## See also

- [dotnet-trace](dotnet-trace.md) to list processes
- [dotnet-trace](dotnet-trace.md) to collect runtime performance traces
- [dotnet-counters](dotnet-counters.md) to check managed memory usage
- [dotnet-dump](dotnet-dump.md) to collect and analyze a dump file
- [dotnet/diagnostics](https://github.com/dotnet/diagnostics/tree/main/documentation/tutorial)
Expand All @@ -275,4 +274,4 @@ You can also delete the dump file that was created.
## Next steps

> [!div class="nextstepaction"]
> [Debug high CPU in .NET Core](debug-highcpu.md)
> [Debug high CPU in .NET](debug-highcpu.md)
Loading
Loading