更新程序删除_old.dll时提示“Access to the path is denied”问题求助
解决DLL更新时被占用无法删除的问题
核心原因
你的应用进程加载该DLL后,CLR会默认锁定程序集文件,即便停止线程,只要程序集仍驻留在内存中,文件就会持续被占用,导致无法删除或替换。
可行解决方案
1. 利用AssemblyLoadContext卸载程序集(.NET Core/.NET 5+)
在.NET Core及后续版本中,可通过自定义AssemblyLoadContext加载DLL,实现按需卸载以释放文件锁:
// 加载DLL时使用可回收的AssemblyLoadContext var alc = new AssemblyLoadContext("CustomDllLoader", isCollectible: true); var targetAssembly = alc.LoadFromAssemblyPath(@"你的目标DLL路径"); // 当不再需要该DLL时,卸载上下文 alc.Unload();
注意:需确保该上下文加载的所有类型实例已被GC回收,否则无法成功卸载。
2. 启用应用域影子复制
影子复制会将程序集复制到临时目录后再加载,原文件不会被锁定,更新时可直接替换:
AppDomainSetup setup = new AppDomainSetup(); setup.ShadowCopyFiles = "true"; // 创建启用影子复制的应用域 AppDomain shadowDomain = AppDomain.CreateDomain("ShadowCopyDomain", null, setup); // 在新域中执行DLL相关逻辑 // ... // 用完后卸载应用域,释放所有资源 AppDomain.Unload(shadowDomain);
3. 拆分独立更新程序(最可靠方案)
将更新逻辑剥离为单独的小工具,避免主进程占用文件:
- 主应用触发更新时,先将新文件下载到临时目录
- 启动更新工具,随后主应用立即退出
- 更新工具等待主进程完全终止后,替换所有目标文件(包括被占用的DLL)
- 替换完成后重启主应用
主应用中启动更新工具的示例代码:
Process.Start(new ProcessStartInfo { FileName = "Updater.exe", Arguments = $"--temp-dir {临时文件路径} --app-dir {主应用目录}", UseShellExecute = false }); Environment.Exit(0);
4. 排查未释放的资源/句柄
- 检查该DLL中是否存在未释放的非托管资源(如文件句柄、网络连接),这类资源可能间接阻止DLL卸载
- 使用Process Explorer工具,查看应用进程对目标DLL的句柄,确认是否有残留引用
临时应急方案
若重命名旧DLL操作成功,可延迟删除旧文件,待下次应用启动时再清理:
// 在应用启动时执行清理 string codeBase = Assembly.GetExecutingAssembly().CodeBase; UriBuilder uri = new UriBuilder(codeBase); string appPath = Regex.Replace(Uri.UnescapeDataString(uri.Path), "Data.exe", "", RegexOptions.IgnoreCase); foreach (string oldFile in Directory.GetFiles(appPath, "*_old.dll")) { try { File.Delete(oldFile); } catch (IOException ex) { // 记录日志,下次启动再尝试删除 } }
内容的提问来源于stack exchange,提问作者nickkoko
相关产品推荐
相关产品推荐

