dotnet / dotnet/aspnetcore

MVC: Minimize memory consumption by routing data structures

Open
#60,000 3 comments 0 reactions 0 assignees View on GitHub
area-mvc
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Is your feature request related to a problem? Please describe the problem.

After startup our application consume significant amount of memory related to MVC routing.
It currently uses .net8.
There are 700+controllers with ~60 method per controller.
Most of controllers inherited from base generic controllers hierarchy, many controllers final type generated at runtime by closing opened generic base controller.
As result at runtime there are many controllers with same method names and parameter names.

After startup we can see next memory consumers:
![Image](https://github.com/user-attachments/assets/ecaaf357-a4fa-4313-8b63-4da205dbf7fa)

There are many duplicated strings in memory (~8% of all allocated objects), where strings referenced by MVC.routing take 1st, 3d, 5th, 9th ..... places

![Image](https://github.com/user-attachments/assets/31e5039a-478d-4daa-9ae2-5147be75f267)

Some examples with string referenced by routing structures directly.

**Parameter name:**
| Value | Wasted | Count |
|---|---|---|
| cancellationToken | 484,5 KB | 14593 |

![Image](https://github.com/user-attachments/assets/d480b818-268f-46a9-8705-0738c1dc2c09)

| Value | Wasted | Count |
|---|---|---|
| filterId | 230,83 KB | 14774 |
| viewId | 173,14 KB | 14776 |

![Image](https://github.com/user-attachments/assets/ea2a41b0-6a2c-421d-92ac-a5040e5488f9)
![Image](https://github.com/user-attachments/assets/b0b96775-0d5e-438c-8219-b3e71e30fbc0)

**Http verb name:**
| Value | Wasted | Count |
|---|---|---|
| POST | 120,36 KB | 15407 |
| GET | 67,28 KB | 11483 |

![Image](https://github.com/user-attachments/assets/b67658f0-ae00-45b7-8209-5abcda203ec2)
![Image](https://github.com/user-attachments/assets/ef0710b3-9f7c-4f4c-888c-995c84cc74ee)

**Controller action name:**
| Value | Wasted | Count |
|---|---|---|
| GetLayoutsPanelForPropertyGridAsync | 50,11 KB | 734 |

![Image](https://github.com/user-attachments/assets/efd2442c-300d-4c23-906c-ec4af752db26)

Also sparse arrays related to MVC routing are in TOP of memory killers.

![Image](https://github.com/user-attachments/assets/5d91b4d8-ad3c-4e02-bfe3-c3f9098e7b46)

| Type | Wasted | Count |
|---|---|---|
| System.Collections.Concurrent.ConcurrentDictionary+VolatileNode[] | 11,83 MB | 43118 |

99.9% of theses Dictionaries contains 1 element
![Image](https://github.com/user-attachments/assets/063a19bb-6387-413a-bfab-05a6fd947e36)

| Type | Wasted | Count |
|---|---|---|
| System.Collections.Generic.Dictionary+Entry>[] | 1,55 MB | 2 |

![Image](https://github.com/user-attachments/assets/8c96bdd2-d60f-4e80-81c1-55b8d84f71a1)

| Type | Wasted | Count |
|---|---|---|
| Microsoft.AspNetCore.Http.Endpoint[] | 1,11 MB | 41485 |

Most of lists contains 1 element from 4 allocated by default
![Image](https://github.com/user-attachments/assets/a50e063f-3572-4993-a283-8cf38e045950)

### Describe the solution you'd like

Some string.Intern() when assigning string in routing data structures like ParameterDescriptor.Name and so on.
Some finalizing of routing initialization where TrimExcess will be called on routing collections.
Probably some nonstandard initial capacity for some routing collections.

### Additional context

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.