-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
Offline report:
Found a strange allocation stack. Source code:
public static bool TryExtractSingleValueHeader(
IHeaderDictionary requestHeaders,
string headerName,
out string headerValue)
{
headerValue = string.Empty;
if (requestHeaders == null || requestHeaders.Keys.Count == 0)
{
return false;
}
var incomingHeaderValues = requestHeaders[headerName];
// There may be multiple values, we will pick the first one.
if (incomingHeaderValues.Count > 0)
{
headerValue = incomingHeaderValues[0];
return true;
}
return false;
}
So where is the LINQ expression? It’s here:
// Microsoft.AspNetCore.HttpSys.Internal.RequestHeaders
public ICollection<string> Keys
{
get
{
return this.PropertiesKeys().Concat(this.Extra.Keys).ToArray<string>();
}
}
For classes like Dictionary<K, V>, getting key collection is cheap because you because you just need to pay for a small key collection object once per dictionary (it will be reused forever). But this here has a super expensive implementation, so do not call it unless you’re willing and able to pay for it.
The strange thing is string allocation is the biggest here:
We do not need to get into the details why strings need to be allocated, because we can just remove the check.
It’s worse than that, the entire Extra headers collection is lazily loaded.
aspnetcore/src/Shared/HttpSys/RequestProcessing/RequestHeaders.cs
Lines 33 to 39 in 14dc33c
| if (_extra == null) | |
| { | |
| var newDict = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase); | |
| GetUnknownHeaders(newDict); | |
| Interlocked.CompareExchange(ref _extra, newDict, null); | |
| } | |
| return _extra; |
IDictionary.Count is also bad
aspnetcore/src/Shared/HttpSys/RequestProcessing/RequestHeaders.cs
Lines 93 to 96 in 14dc33c
| public int Count | |
| { | |
| get { return PropertiesKeys().Count() + Extra.Count; } | |
| } |
Expected Behavior
No response
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
No response
Anything else?
No response
