feat(cordis): 完成阶段5访问介导与诊断
This commit is contained in:
+52
-6
@@ -15,6 +15,7 @@ namespace ShrinkModFramework
|
||||
public string Path;
|
||||
public string Revision;
|
||||
public Assembly Assembly;
|
||||
public long LoadedBytes;
|
||||
}
|
||||
|
||||
internal sealed class RevisionState
|
||||
@@ -27,10 +28,11 @@ namespace ShrinkModFramework
|
||||
|
||||
private static readonly Dictionary<string, ExternalAssemblyRevision> CurrentAssemblyRevisions =
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
private static readonly HashSet<Assembly> ExternalAssemblyHistory = new();
|
||||
private static readonly Dictionary<Assembly, ExternalAssemblyRevision> ExternalAssemblyHistory = new();
|
||||
private static readonly Dictionary<string, string> KnownAssemblyFiles = new(StringComparer.OrdinalIgnoreCase);
|
||||
private static readonly object ResolveLock = new();
|
||||
private static bool _resolveRegistered;
|
||||
private static int _lastWarnedResidentCount;
|
||||
|
||||
public static IReadOnlyList<Assembly> LoadExternalAssemblies(ShrinkModFrameworkSettings settings, bool verboseLogging)
|
||||
{
|
||||
@@ -82,18 +84,22 @@ namespace ShrinkModFramework
|
||||
}
|
||||
|
||||
var pdbPath = Path.ChangeExtension(dllPath, ".pdb");
|
||||
var assembly = File.Exists(pdbPath)
|
||||
? Assembly.Load(bytes, File.ReadAllBytes(pdbPath))
|
||||
byte[] pdbBytes = null;
|
||||
if (File.Exists(pdbPath))
|
||||
pdbBytes = File.ReadAllBytes(pdbPath);
|
||||
var assembly = pdbBytes != null
|
||||
? Assembly.Load(bytes, pdbBytes)
|
||||
: Assembly.Load(bytes);
|
||||
|
||||
var loadedRevision = new ExternalAssemblyRevision
|
||||
{
|
||||
Path = dllPath,
|
||||
Revision = revision,
|
||||
Assembly = assembly
|
||||
Assembly = assembly,
|
||||
LoadedBytes = bytes.LongLength + (pdbBytes?.LongLength ?? 0L)
|
||||
};
|
||||
CurrentAssemblyRevisions[dllPath] = loadedRevision;
|
||||
ExternalAssemblyHistory.Add(assembly);
|
||||
ExternalAssemblyHistory[assembly] = loadedRevision;
|
||||
|
||||
if (verboseLogging)
|
||||
Debug.Log($"[ShrinkModFramework] 已加载外部模组程序集:{assembly.GetName().Name} ({revision[..12]})");
|
||||
@@ -104,6 +110,8 @@ namespace ShrinkModFramework
|
||||
}
|
||||
}
|
||||
|
||||
WarnIfResidentLimitExceeded(settings);
|
||||
|
||||
foreach (var missingPath in CurrentAssemblyRevisions.Keys
|
||||
.Where(path => !presentPaths.Contains(path))
|
||||
.ToArray())
|
||||
@@ -124,7 +132,30 @@ namespace ShrinkModFramework
|
||||
}
|
||||
|
||||
internal static bool IsExternalAssembly(Assembly assembly) =>
|
||||
assembly != null && ExternalAssemblyHistory.Contains(assembly);
|
||||
assembly != null && ExternalAssemblyHistory.ContainsKey(assembly);
|
||||
|
||||
internal static ShrinkExternalAssemblyDiagnostic CaptureDiagnostic(int softLimit)
|
||||
{
|
||||
var normalizedLimit = Math.Max(1, softLimit);
|
||||
var currentAssemblies = new HashSet<Assembly>(
|
||||
CurrentAssemblyRevisions.Values.Select(item => item.Assembly));
|
||||
var revisions = ExternalAssemblyHistory.Values
|
||||
.OrderBy(item => item.Path, StringComparer.OrdinalIgnoreCase)
|
||||
.ThenBy(item => item.Revision, StringComparer.Ordinal)
|
||||
.Select(item => new ShrinkExternalAssemblyRevisionDiagnostic(
|
||||
item.Path,
|
||||
item.Revision,
|
||||
item.Assembly.GetName().Name ?? string.Empty,
|
||||
item.LoadedBytes,
|
||||
currentAssemblies.Contains(item.Assembly)))
|
||||
.ToArray();
|
||||
|
||||
return new ShrinkExternalAssemblyDiagnostic(
|
||||
CurrentAssemblyRevisions.Count,
|
||||
revisions,
|
||||
revisions.Sum(item => item.LoadedBytes),
|
||||
normalizedLimit);
|
||||
}
|
||||
|
||||
internal static RevisionState CaptureState()
|
||||
{
|
||||
@@ -193,6 +224,21 @@ namespace ShrinkModFramework
|
||||
{
|
||||
ResetForTesting();
|
||||
ExternalAssemblyHistory.Clear();
|
||||
_lastWarnedResidentCount = 0;
|
||||
}
|
||||
|
||||
private static void WarnIfResidentLimitExceeded(ShrinkModFrameworkSettings settings)
|
||||
{
|
||||
var limit = Math.Max(1, settings != null ? settings.externalAssemblyRevisionSoftLimit : 16);
|
||||
var residentCount = ExternalAssemblyHistory.Count;
|
||||
if (residentCount < limit || residentCount == _lastWarnedResidentCount)
|
||||
return;
|
||||
|
||||
_lastWarnedResidentCount = residentCount;
|
||||
var bytes = ExternalAssemblyHistory.Values.Sum(item => item.LoadedBytes);
|
||||
Debug.LogWarning(
|
||||
$"[ShrinkModFramework] 外部 DLL 常驻 revision 已达到 {residentCount} 个(载入文件约 {bytes} bytes," +
|
||||
$"软阈值 {limit})。Mono 无法卸载这些 Assembly;建议在维护窗口执行 Domain Reload 或重启进程。");
|
||||
}
|
||||
|
||||
private static string ComputeSha256(byte[] bytes)
|
||||
|
||||
Reference in New Issue
Block a user