重复执行C#脚本时出现句柄泄漏问题求助
解决CSharpScript重复执行导致的句柄泄漏问题
你遇到的句柄泄漏是因为每次调用CSharpScript.Create或CSharpScript.RunAsync时,都会生成新的动态程序集,这些程序集默认加载到不可回收的上下文里,相关资源(如文件句柄、内存映射句柄)无法被及时释放,哪怕手动触发GC也没用。
解决方案1:复用Script实例(脚本内容固定时)
如果执行的脚本内容不变,只需要创建和编译一次Script,重复执行即可,从根源避免重复生成资源:
using Microsoft.CodeAnalysis.CSharp.Scripting; // 仅初始化一次脚本 var script = CSharpScript.Create("bool test = true;"); script.Compile(); while (true) { using (var state = script.RunAsync()) { var result = state.Result; } }
解决方案2:使用可回收AssemblyLoadContext(脚本内容动态变化时)
如果每次执行的脚本内容不同,需要用AssemblyLoadContext隔离动态生成的程序集,确保资源可以被卸载:
using System.Runtime.Loader; using Microsoft.CodeAnalysis.CSharp.Scripting; while (true) { // 创建可回收的AssemblyLoadContext using var alc = new AssemblyLoadContext(null, isCollectible: true); var scriptOptions = ScriptOptions.Default.WithAssemblyLoadContext(alc); using (var state = CSharpScript.RunAsync("bool test = true;", scriptOptions)) { var result = state.Result; } // 显式卸载ALC并触发GC回收资源 alc.Unload(); GC.Collect(); GC.WaitForPendingFinalizers(); }
原因说明
- 默认情况下,
CSharpScript生成的动态程序集会被加载到全局AssemblyLoadContext,这个上下文不可回收,程序集及其关联句柄会一直被进程持有。 - 可回收
AssemblyLoadContext可以单独管理动态程序集,调用Unload()后,该上下文内的所有资源会被标记为可回收,配合GC可以释放相关句柄。
内容的提问来源于stack exchange,提问作者filtrow
相关产品推荐
相关产品推荐

