- Fixed assembly unloading. However, requires 'plugin_forcerungc' to be run multiple times over ~30 seconds at the main menu.
This commit is contained in:
@@ -332,17 +332,9 @@ namespace Barotrauma
|
|||||||
void RunStateUnloaded_OnEnter(State<RunState> currentState)
|
void RunStateUnloaded_OnEnter(State<RunState> currentState)
|
||||||
{
|
{
|
||||||
Logger.LogMessage("LuaCs unloaded state entered");
|
Logger.LogMessage("LuaCs unloaded state entered");
|
||||||
|
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
||||||
if (PackageManagementService.IsAnyPackageRunning())
|
DisposeLuaCsConfig();
|
||||||
{
|
Logger.LogResults(PackageManagementService.UnloadAllPackages());
|
||||||
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PackageManagementService.IsAnyPackageLoaded())
|
|
||||||
{
|
|
||||||
DisposeLuaCsConfig();
|
|
||||||
Logger.LogResults(PackageManagementService.UnloadAllPackages());
|
|
||||||
}
|
|
||||||
|
|
||||||
EventService.Reset();
|
EventService.Reset();
|
||||||
ConfigService.Reset();
|
ConfigService.Reset();
|
||||||
@@ -362,11 +354,7 @@ namespace Barotrauma
|
|||||||
void RunStateLoadedNoExec_OnEnter(State<RunState> currentState)
|
void RunStateLoadedNoExec_OnEnter(State<RunState> currentState)
|
||||||
{
|
{
|
||||||
Logger.LogMessage("LuaCs no execution state entered");
|
Logger.LogMessage("LuaCs no execution state entered");
|
||||||
|
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
||||||
if (PackageManagementService.IsAnyPackageRunning())
|
|
||||||
{
|
|
||||||
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PackageManagementService.IsAnyPackageLoaded())
|
if (!PackageManagementService.IsAnyPackageLoaded())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public Result<Assembly> CompileScriptAssembly([NotNull] string assemblyName,
|
public Result<Assembly> CompileScriptAssembly([NotNull] string assemblyName,
|
||||||
bool compileWithInternalAccess,
|
bool compileWithInternalAccess,
|
||||||
ImmutableArray<SyntaxTree> syntaxTrees,
|
ImmutableArray<SyntaxTree> syntaxTrees,
|
||||||
@@ -348,6 +349,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public FluentResults.Result<Assembly> LoadAssemblyFromFile(string assemblyFilePath,
|
public FluentResults.Result<Assembly> LoadAssemblyFromFile(string assemblyFilePath,
|
||||||
ImmutableArray<string> additionalDependencyPaths)
|
ImmutableArray<string> additionalDependencyPaths)
|
||||||
{
|
{
|
||||||
@@ -434,6 +436,8 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public FluentResults.Result<Assembly> GetAssemblyByName(string assemblyName)
|
public FluentResults.Result<Assembly> GetAssemblyByName(string assemblyName)
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
@@ -481,6 +485,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public FluentResults.Result<ImmutableArray<Type>> GetTypesInAssemblies()
|
public FluentResults.Result<ImmutableArray<Type>> GetTypesInAssemblies()
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
@@ -501,6 +506,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public IEnumerable<Type> UnsafeGetTypesInAssemblies()
|
public IEnumerable<Type> UnsafeGetTypesInAssemblies()
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
@@ -529,6 +535,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public Result<Type> GetTypeInAssemblies(string typeName)
|
public Result<Type> GetTypeInAssemblies(string typeName)
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
@@ -557,14 +564,12 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
return; // we don't want to invoke events twice nor cause strong GC handles.
|
return; // we don't want to invoke events twice nor cause strong GC handles.
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
this.Unload();
|
this.Unload();
|
||||||
this.DisposeInternal();
|
GC.SuppressFinalize(this);
|
||||||
// we want to call base finalizers
|
|
||||||
//GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~AssemblyLoader()
|
~AssemblyLoader()
|
||||||
{
|
{
|
||||||
this.DisposeInternal();
|
this.Unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUnload(AssemblyLoadContext context)
|
private void OnUnload(AssemblyLoadContext context)
|
||||||
@@ -579,9 +584,8 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
Thread.Sleep(1000/Timing.FixedUpdateRate-1);
|
Thread.Sleep(1000/Timing.FixedUpdateRate-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var wf = new WeakReference<IAssemblyLoaderService>(this);
|
|
||||||
_loadedAssemblyData.Clear();
|
|
||||||
_onUnload?.Invoke(this);
|
_onUnload?.Invoke(this);
|
||||||
|
this.DisposeInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeInternal()
|
private void DisposeInternal()
|
||||||
@@ -592,6 +596,9 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
base.Unloading -= OnUnload;
|
base.Unloading -= OnUnload;
|
||||||
this._dependencyResolvers.Clear();
|
this._dependencyResolvers.Clear();
|
||||||
this._loadedAssemblyData.Clear();
|
this._loadedAssemblyData.Clear();
|
||||||
|
|
||||||
|
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
|
||||||
|
GC.WaitForFullGCComplete(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Assembly Load(AssemblyName assemblyName)
|
protected override Assembly Load(AssemblyName assemblyName)
|
||||||
@@ -660,6 +667,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
public readonly ImmutableArray<Type> Types;
|
public readonly ImmutableArray<Type> Types;
|
||||||
public readonly ImmutableDictionary<string, Type> TypesByName;
|
public readonly ImmutableDictionary<string, Type> TypesByName;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
public AssemblyData(Assembly assembly, byte[] assemblyImage)
|
public AssemblyData(Assembly assembly, byte[] assemblyImage)
|
||||||
{
|
{
|
||||||
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
|
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
|
||||||
@@ -669,6 +677,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
TypesByName = Types.ToImmutableDictionary(type => type.FullName, type => type);
|
TypesByName = Types.ToImmutableDictionary(type => type.FullName, type => type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
public AssemblyData(Assembly assembly, string path)
|
public AssemblyData(Assembly assembly, string path)
|
||||||
{
|
{
|
||||||
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
|
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
|
||||||
@@ -696,6 +705,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
|||||||
HashCode = AssemblyName.GetHashCode();
|
HashCode = AssemblyName.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
public AssemblyOrStringKey(string assemblyName)
|
public AssemblyOrStringKey(string assemblyName)
|
||||||
{
|
{
|
||||||
if (assemblyName.IsNullOrWhiteSpace())
|
if (assemblyName.IsNullOrWhiteSpace())
|
||||||
|
|||||||
+103
-76
@@ -89,6 +89,7 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
private ImmutableArray<MetadataReference> _baseMetadataReferences = ImmutableArray<MetadataReference>.Empty;
|
private ImmutableArray<MetadataReference> _baseMetadataReferences = ImmutableArray<MetadataReference>.Empty;
|
||||||
private ImmutableArray<MetadataReference> _baseMetadataReferencesNonPublicized = ImmutableArray<MetadataReference>.Empty;
|
private ImmutableArray<MetadataReference> _baseMetadataReferencesNonPublicized = ImmutableArray<MetadataReference>.Empty;
|
||||||
|
|
||||||
|
private static readonly int GC_COLLECT_WAIT_TIME = 2000;
|
||||||
|
|
||||||
private IEnumerable<MetadataReference> BaseMetadataReferences
|
private IEnumerable<MetadataReference> BaseMetadataReferences
|
||||||
{
|
{
|
||||||
@@ -215,6 +216,7 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
private IEventService _pluginEventService;
|
private IEventService _pluginEventService;
|
||||||
private Lazy<ILuaPatcher> _pluginLuaPatcherService;
|
private Lazy<ILuaPatcher> _pluginLuaPatcherService;
|
||||||
private Func<IConsoleCommandsService> _consoleCommandServiceFactory;
|
private Func<IConsoleCommandsService> _consoleCommandServiceFactory;
|
||||||
|
private readonly IConsoleCommandsService _internalConsoleCommandsService;
|
||||||
private ILuaCsInfoProvider _luaCsInfoProvider;
|
private ILuaCsInfoProvider _luaCsInfoProvider;
|
||||||
private readonly ConcurrentDictionary<ContentPackage, IAssemblyLoaderService> _assemblyLoaders = new();
|
private readonly ConcurrentDictionary<ContentPackage, IAssemblyLoaderService> _assemblyLoaders = new();
|
||||||
private readonly ConcurrentDictionary<Type, ContentPackage> _pluginPackageLookup = new();
|
private readonly ConcurrentDictionary<Type, ContentPackage> _pluginPackageLookup = new();
|
||||||
@@ -244,6 +246,18 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
_pluginLuaPatcherService = pluginLuaPatcherService;
|
_pluginLuaPatcherService = pluginLuaPatcherService;
|
||||||
_consoleCommandServiceFactory = consoleCommandServiceFactory;
|
_consoleCommandServiceFactory = consoleCommandServiceFactory;
|
||||||
_luaCsInfoProvider = luaCsInfoProvider;
|
_luaCsInfoProvider = luaCsInfoProvider;
|
||||||
|
_internalConsoleCommandsService = consoleCommandServiceFactory.Invoke();
|
||||||
|
|
||||||
|
RegisterCommands(_internalConsoleCommandsService);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterCommands(IConsoleCommandsService cmdService)
|
||||||
|
{
|
||||||
|
cmdService.RegisterCommand("plugin_forcerungc", "Forces the GC to run", cmds =>
|
||||||
|
{
|
||||||
|
_logger.LogMessage("Forcing GC run.");
|
||||||
|
RunGC(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceContainer CreatePluginServiceContainer()
|
private ServiceContainer CreatePluginServiceContainer()
|
||||||
@@ -310,11 +324,13 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public bool TryGetPackageForPlugin<TPlugin>(out ContentPackage ownerPackage)
|
public bool TryGetPackageForPlugin<TPlugin>(out ContentPackage ownerPackage)
|
||||||
{
|
{
|
||||||
return _pluginPackageLookup.TryGetValue(typeof(TPlugin), out ownerPackage);
|
return _pluginPackageLookup.TryGetValue(typeof(TPlugin), out ownerPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public Type GetType(string typeName, bool isByRefType = false, bool includeInterfaces = false,
|
public Type GetType(string typeName, bool isByRefType = false, bool includeInterfaces = false,
|
||||||
bool includeDefaultContext = true)
|
bool includeDefaultContext = true)
|
||||||
{
|
{
|
||||||
@@ -497,7 +513,7 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public FluentResults.Result LoadAssemblyResources(ImmutableArray<IAssemblyResourceInfo> resources)
|
public FluentResults.Result LoadAssemblyResources(ImmutableArray<IAssemblyResourceInfo> resources)
|
||||||
{
|
{
|
||||||
if (resources.IsDefaultOrEmpty)
|
if (resources.IsDefaultOrEmpty)
|
||||||
@@ -727,7 +743,7 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
.Replace(" Barotrauma.Networking.Client.ClientList", " ModUtils.Client.ClientList")
|
.Replace(" Barotrauma.Networking.Client.ClientList", " ModUtils.Client.ClientList")
|
||||||
.Replace("ItemPrefab.GetItemPrefab", "ModUtils.ItemPrefab.GetItemPrefab");
|
.Replace("ItemPrefab.GetItemPrefab", "ModUtils.ItemPrefab.GetItemPrefab");
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntPtr OnAssemblyLoaderResolvingUnmanaged(Assembly callerAssembly, string targetAssemblyName)
|
private IntPtr OnAssemblyLoaderResolvingUnmanaged(Assembly callerAssembly, string targetAssemblyName)
|
||||||
{
|
{
|
||||||
Guard.IsNull(callerAssembly, nameof(callerAssembly));
|
Guard.IsNull(callerAssembly, nameof(callerAssembly));
|
||||||
@@ -800,21 +816,58 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
{
|
{
|
||||||
_eventService?.Value?.PublishEvent<IEventAssemblyUnloading>(sub => sub.OnAssemblyUnloading(assembly));
|
_eventService?.Value?.PublishEvent<IEventAssemblyUnloading>(sub => sub.OnAssemblyUnloading(assembly));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_unloadingAssemblyLoaders.Add(loader, loader.OwnerPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
public FluentResults.Result UnloadManagedAssemblies()
|
public FluentResults.Result UnloadManagedAssemblies()
|
||||||
{
|
{
|
||||||
using var lck = _operationsLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
using var lck = _operationsLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
if (_assemblyLoaders.Count == 0)
|
|
||||||
{
|
|
||||||
return FluentResults.Result.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
var results = new FluentResults.Result();
|
var results = new FluentResults.Result();
|
||||||
|
|
||||||
results.WithReasons(UnsafeDisposeManagedTypeInstances().Reasons);
|
if (!_pluginInstances.IsEmpty)
|
||||||
|
{
|
||||||
|
foreach (var instance in _pluginInstances.SelectMany(kvp => kvp.Value))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
instance.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
results.WithError(new ExceptionalError(e));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_pluginInstances.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pluginEventService is not null)
|
||||||
|
{
|
||||||
|
_eventService.Value.RemoveDispatcherEventService(_pluginEventService);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pluginEventService.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
results.WithError(new ExceptionalError(e));
|
||||||
|
}
|
||||||
|
_pluginEventService = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pluginInjectorContainer?.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
results.WithError(new ExceptionalError(e));
|
||||||
|
}
|
||||||
|
_pluginInjectorContainer = null;
|
||||||
|
|
||||||
ReflectionUtils.ResetCache();
|
ReflectionUtils.ResetCache();
|
||||||
foreach (var loaderService in _assemblyLoaders)
|
foreach (var loaderService in _assemblyLoaders)
|
||||||
@@ -822,7 +875,6 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
loaderService.Value.Dispose();
|
loaderService.Value.Dispose();
|
||||||
_unloadingAssemblyLoaders.Add(loaderService.Value, loaderService.Key);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -832,41 +884,7 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
|
|
||||||
_assemblyLoaders.Clear();
|
_assemblyLoaders.Clear();
|
||||||
_storageService.PurgeCache();
|
_storageService.PurgeCache();
|
||||||
GC.Collect();
|
_pluginPackageLookup.Clear();
|
||||||
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true);
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
GC.WaitForFullGCComplete(1000);
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
// Print still loaded assembly load ctx after giving some time
|
|
||||||
CoroutineManager.Invoke(() =>
|
|
||||||
{
|
|
||||||
if (!_unloadingAssemblyLoaders.Any())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.AppendLine("The following ContentPackages have not unloaded their assemblies:");
|
|
||||||
|
|
||||||
foreach (var kvp in _unloadingAssemblyLoaders.ToImmutableArray())
|
|
||||||
{
|
|
||||||
sb.AppendLine($"- '{kvp.Value.Name}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Use DebugConsole in case logger is null by the time this executes.
|
|
||||||
if (_logger is null)
|
|
||||||
{
|
|
||||||
DebugConsole.LogError(sb.ToString());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogWarning(sb.ToString());
|
|
||||||
}
|
|
||||||
}, 3.0f);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clear native libraries
|
// clear native libraries
|
||||||
if (_loadedNativeLibraries.Any())
|
if (_loadedNativeLibraries.Any())
|
||||||
@@ -886,49 +904,58 @@ public class PluginManagementService : IAssemblyManagementService
|
|||||||
|
|
||||||
_loadedNativeLibraries.Clear();
|
_loadedNativeLibraries.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RunGC(false);
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FluentResults.Result UnsafeDisposeManagedTypeInstances()
|
private void RunGC(bool logResults)
|
||||||
{
|
{
|
||||||
var results = new FluentResults.Result();
|
int maxGen = GC.MaxGeneration;
|
||||||
|
GC.RegisterForFullGCNotification(maxGen, 10);
|
||||||
if (!_pluginInstances.IsEmpty)
|
for (int gcGen = 0; gcGen < maxGen; gcGen++)
|
||||||
{
|
{
|
||||||
foreach (var instance in _pluginInstances.SelectMany(kvp => kvp.Value))
|
GC.Collect(maxGen, GCCollectionMode.Aggressive, true, true);
|
||||||
|
var confirmationToken = GC.WaitForFullGCComplete(GC_COLLECT_WAIT_TIME);
|
||||||
|
if (logResults)
|
||||||
{
|
{
|
||||||
try
|
_logger.LogWarning($"GC Pass # {gcGen} completed. Completion status: {confirmationToken.ToString()}");
|
||||||
{
|
|
||||||
instance.Dispose();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
results.WithError(new ExceptionalError(e));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GC.CancelFullGCNotification();
|
||||||
|
|
||||||
if (_pluginEventService is not null)
|
// Print still loaded assembly load ctx after giving some time
|
||||||
|
if (logResults)
|
||||||
{
|
{
|
||||||
_eventService.Value.RemoveDispatcherEventService(_pluginEventService);
|
CoroutineManager.Invoke(() =>
|
||||||
_pluginEventService = null;
|
{
|
||||||
|
if (!_unloadingAssemblyLoaders.Any())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.AppendLine("The following ContentPackages have not unloaded their assemblies:");
|
||||||
|
|
||||||
|
foreach (var kvp in _unloadingAssemblyLoaders.ToImmutableArray())
|
||||||
|
{
|
||||||
|
sb.AppendLine($"- '{kvp.Value.Name}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use DebugConsole in case logger is null by the time this executes.
|
||||||
|
if (_logger is null)
|
||||||
|
{
|
||||||
|
DebugConsole.LogError(sb.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning(sb.ToString());
|
||||||
|
}
|
||||||
|
}, GC.MaxGeneration * GC_COLLECT_WAIT_TIME/1000f);
|
||||||
}
|
}
|
||||||
try
|
|
||||||
{
|
|
||||||
_pluginInjectorContainer.Dispose();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
results.WithError(new ExceptionalError(e));
|
|
||||||
}
|
|
||||||
_pluginInjectorContainer = null;
|
|
||||||
|
|
||||||
_pluginInstances.Clear();
|
|
||||||
_pluginPackageLookup.Clear();
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<Assembly> GetLoadedAssembly(OneOf<AssemblyName, string> assemblyName, in Guid[] excludedContexts)
|
public Result<Assembly> GetLoadedAssembly(OneOf<AssemblyName, string> assemblyName, in Guid[] excludedContexts)
|
||||||
|
|||||||
Reference in New Issue
Block a user