-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Closed
Labels
Milestone
Description
Description
The AssemblyLoadContext of any type that has undergone data contract serialization cannot be unloaded / collected. The specific offender is DataContractCriticalHelper, which has a few static caches and also retains a reference to the most-recently-serialized type.
Reproduction Steps
- Create a collectible AssemblyLoadContext
- Load a DataContractSerializable type into the collectible ALC
- Instantiate the collectible type
- Serialise the instance using something like:
var ser = new DataContractSerializer(type);
using (var ms = new System.IO.MemoryStream())
{
ser.WriteObject(ms, document);
var bytes = ms.ToArray();
return System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}- Invoke Unload() on the collectible ALC
- Trigger a garbage collection (collect / finalise / collect)
- Review loaded assemblies using a debugger or something like AppDomain.CurrentDomain.GetAssemblies()
- Observe that the collectible ALC / assembly has not unloaded.
- Repeat steps but skip step 4 and observer that the ALC / assembly has unloaded properly
Expected behavior
Unloading and collecting results in proper collection of collectible types / assemblies / contexts.
Actual behavior
Collectible types / assemblies / contexts that have been data contract serialised cannot be collected.
Regression?
No response
Known Workarounds
The following code allows proper collection to occur:
private static void ClearDataContractCaches()
{
var t = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Single(x => x.Name == "DataContractCriticalHelper");
var staticCache = t.GetFields(BindingFlags.NonPublic | BindingFlags.Static).Select(x => x.GetValue(t)).ToArray();
foreach (var dictionary in staticCache.OfType<IDictionary>())
dictionary.Clear();
foreach (var array in staticCache.OfType<Array>())
{
for (var i = 0; i < array.Length; I++)
{
array.SetValue(null, i);
}
}
var handleBreaker = new DataContractSerializer(typeof(object));
var o = new object();
using (var ms = new MemoryStream())
{
handleBreaker.WriteObject(ms, o);
}
}Configuration
.NET 6
macOS Ventura 13.0
ARM64
Other information
No response
exally and DeVilAus