-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Description
I have plugin, loaded into a collectible AssemblyLoadContext.
When I try to unload the assembly, it never unloads, since a refenrece to something which belongs to my collectible assembly stored in the System.Dynamic.Utils.TypeExtensions.s_paramInfoCache._entries array.
Reproduction Steps
I don't know how to reproduce easily, but I logged the Entry from the cache:
Method: System.Linq.IQueryable1[<>f__AnonymousType05[System.Guid,System.String,System.String,Rsoe.PannonRis.Framework.Common.Infrastructure.Nts.enums.LanguageCodeEnum,System.DateTime]] Select[RisMessage,<>f__AnonymousType05](System.Linq.IQueryable1[Rsoe.PannonRis.Framework.Common.Infrastructure.Nts.RisMessage], System.Linq.Expressions.Expression1[System.Func2[Rsoe.PannonRis.Framework.Common.Infrastructure.Nts.RisMessage,<>f__AnonymousType05[System.Guid,System.String,System.String,Rsoe.PannonRis.Framework.Common.Infrastructure.Nts.enums.LanguageCodeEnum,System.DateTime]]])`
Parameters: System.Linq.IQueryable1[Rsoe.PannonRis.Framework.Common.Infrastructure.Nts.RisMessage] source,System.Linq.Expressions.Expression1[System.Func2[Rsoe.PannonRis.Framework.Common.Infrastructure.Nts.RisMessage,<>f__AnonymousType05[System.Guid,System.String,System.String,Rsoe.PannonRis.Framework.Common.Infrastructure.Nts.enums.LanguageCodeEnum,System.DateTime]]] selector
The assebmly I want to unload is: RSOE.PannonRIS.Framework.Services
I can't see this namespace in the logged method/parameters, but the anonymouse type is in this assembly:
// q is NHibernate IQueryable
var messages = q.Select(t => new
{
t.Id,
t.Identification.Originator,
t.Identification.From,
t.Identification.LanguageCode,
t.EntityLastUpdated,
}).ToList();
Expected behavior
My collectible assebmly unloads
Actual behavior
Not unloading.
Regression?
No response
Known Workarounds
I can clear this cache with reflection:
public static void ClearCacheDynamic(int idx)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
var teType = assembly.GetType("System.Dynamic.Utils.TypeExtensions");
if (teType != null)
{
var cacheField = teType.GetField("s_paramInfoCache", BindingFlags.Static | BindingFlags.NonPublic);
var cacheDictType = cacheField.FieldType;
var entriesField = cacheDictType.GetField("_entries", BindingFlags.Instance | BindingFlags.NonPublic);
var arr = (object[])entriesField.GetValue(cacheField.GetValue(null));
var entryType = cacheDictType.GetNestedType("Entry", BindingFlags.NonPublic).MakeGenericType(cacheDictType.GenericTypeArguments);
var hashField = entryType.GetField("_hash", BindingFlags.Instance | BindingFlags.NonPublic);
var keyField = entryType.GetField("_key", BindingFlags.Instance | BindingFlags.NonPublic);
var valueField = entryType.GetField("_value", BindingFlags.Instance | BindingFlags.NonPublic);
for (int i = 0; i < arr.Length; i++)
{
if (idx != -1 && i != idx)
{
continue;
}
if (arr[i] != null)
{
int hash = (int)hashField.GetValue(arr[i]);
var key = (MethodBase)keyField.GetValue(arr[i]);
var parameters = (ParameterInfo[])valueField.GetValue(arr[i]);
string paramsStr = string.Join(",", parameters);
ServiceLogger.Instance.Info($"Entry {i}: {hash} {key}, parameters: {paramsStr}");
}
arr[i] = null;
}
//cacheField.SetValue(null,
// Activator.CreateInstance(cacheField.FieldType, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, [75], null));
}
}
catch (Exception ex)
{
ServiceLogger.Instance.Info($"Failed to clear paramInfoCache: {assembly.FullName}. {ex.Message}");
}
}
}
After clearing the appropriate element (I did it one by one) the assembly unloads.
Configuration
.NET 9.0.9
Win 11, all updates installed
x64
Other information
No response