一、DebuggerAttribute
DebuggerAttribute为作用在程序集上的特性,按照微软文档对该特性的描述,该特性用于修改运行时实时 (JIT) 调试的代码生成。而在Debug下编译并生成的程序集,JIT会将变量保存至方法结束。这将影响以下代码的一些表现。
1、Debug
程序集在Debug模式下默认的DebuggerAttribute如下,通过ILspy可以看到。
// D:\vs2019 proj\EventTest\EventTest\bin\Debug\net6.0\EventTest.dll // EventTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null // Global type: <Module> // Entry point: EventTest.Program.Main // Architecture: AnyCPU (64-bit preferred) // Runtime: v4.0.30319 // This assembly was compiled using the /deterministic option. // Hash algorithm: SHA1 // Debug info: Loaded from portable PDB: D:\vs2019 proj\EventTest\EventTest\bin\Debug\net6.0\EventTest.pdb using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("EventTest")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EventTest")] [assembly: AssemblyTitle("EventTest")] [assembly: AssemblyVersion("1.0.0.0")]ILspy on assembly
控制台应用程序的Main函数是这样的。
private class TestClass { public void Test() { Subscriber sub = new Subscriber(); sub = null; GC.Collect(); } } private static void Main(string[] args) { TestClass testClass = new TestClass(); testClass.Test(); Console.WriteLine("Test方法结束"); Console.ReadLine(); Debugger.Break(); }
public class Subscriber { public Subscriber() { Console.WriteLine("Subscriber created"); } public void Subscribe(object o, EventArgs e) { Console.WriteLine("Subscriber " + DateTime.Now); } ~Subscriber() { Console.WriteLine("Subscriber Finalize"); } }Subscriber
//Output Subscriber created Test方法结束
运行后将不会看到Subscriber的终结器被执行。
2、Release
将以上代码以Release模式下编译后运行。在程序结束前执行了Subscriber的终结器。
//Output Subscriber created Test方法结束 Subscriber Finalize
Release模式下的DebuggerAttribute。
using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("EventTest")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EventTest")] [assembly: AssemblyTitle("EventTest")] [assembly: AssemblyVersion("1.0.0.0")]ILspy on assembly with release mode
二、在Debug下回收对象
1、在Test()方法外回收
前文提过,在Debug下编译并生成的程序集,JIT会将变量保存至方法结束,所以TestClass.Test()方法中的GC.collect()没有把对象回收掉。那么在Test()方法结束后再执行一次回收即可把GC.Collect()即可把对象回收掉。
注:其实不管是Debug还是在Release下,TestClass.Test()方法中的Subscriber对象在线程离开Test()方法后会被变为无根对象,其所占用的内存空间在下一次GC的时候回收。
2、在Test()方法内回收
既然是通过DebuggerAttribute影响JIT对变象的保存,那么在Debug模式下指定DebuggerAttribute即可改变JIT的前述的行为。
//MyAssemblyInfo.cs using System.Diagnostics; [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default)]MyAssemblyInfo.cs
在项目中新建文件,内容如上。(注:如果是Net framework项目,可以在项目自带的AssemblyInfo加入以上内容)
将DebuggingModes指定为Default即可让Subscriber对象在Test内回收。终结器的执行顺序在Test方法之后是因为执行终结器的时机是由GC决定,并不由程序员决定。
//Output Subscriber created Test方法结束 Subscriber Finalize
更多信息查看以下链接:
终结器 - C# 编程指南 - C# | Microsoft Learn
GC.Collect 方法 (System) | Microsoft Learn
DebuggableAttribute 类 (System.Diagnostics) | Microsoft Learn
DebuggableAttribute.DebuggingModes 枚举 (System.Diagnostics) | Microsoft Learn
C # 编译器选项 - 代码生成选项 - C# | Microsoft Learn
标签:assembly,C#,System,Subscriber,Test,GC,Release,EventTest,Debug From: https://www.cnblogs.com/mikodopants/p/17680550.html