【问题标题】:AppDomain.Unload doesn't release the assembly I loaded up with Reflection [duplicate]AppDomain.Unload 没有释放我用反射加载的程序集[重复]
【发布时间】:2009-09-23 19:37:50
【问题描述】:

可能重复:
how to delete the pluginassembly after AppDomain.Unload(domain)

在临时 AppDomain 中加载程序集以读取其 GetUsedReferences 属性时,我遇到了一个问题。一旦我这样做了,我调用 AppDomain.Unload(tempDomain) 然后我尝试通过删除文件来清理我的烂摊子。失败是因为文件被锁定。我卸载了临时域!任何想法或建议将不胜感激。这是我的一些代码:

//I already have btyes for the .dll and the .pdb from the actual files
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ApplicationBase = Environment.CurrentDirectory;
domainSetup.ShadowCopyFiles = "true";
domainSetup.CachePath = Environment.CurrentDirectory;
AppDomain tempAppDomain = AppDomain.CreateDomain("TempAppDomain", AppDomain.CurrentDomain.Evidence, domainSetup);

//Load up the temp assembly and do stuff
Assembly projectAssembly = tempAppDomain.Load(assemblyFileBuffer, symbolsFileBuffer);

//Then I'm trying to clean up
AppDomain.Unload(tempAppDomain);
tempAppDomain = null;
File.Delete(tempAssemblyFile); //I even try to force GC
File.Delete(tempSymbolsFile);

无论如何,删除失败,因为文件仍然被锁定。他们不应该因为我卸载了临时 AppDomain 而被释放吗?

【问题讨论】:

  • 您自己动态编译程序集吗?如果是这样,那么您甚至可能不必将其作为文件保存。
  • 我正在自己编译程序集。以下是我目前正在尝试的步骤: 1. 编译程序集 2. 为程序集和 .pdb 制作临时文件 3. 将它们加载到新的 AppDomain 中(严格来说,以便我可以尝试卸载它并释放文件) 4 . 加载一个程序集以便我可以得到它的引用 5. 卸载新的临时 AppDomain 6. 尝试清理临时文件 *但它们仍然被锁定 4.

标签: .net assemblies


【解决方案1】:

我知道这是一个老问题,但仍然没有公认的答案。我偶然发现了这个问题以寻找答案,因此我认为发布我在此处找到的解决方案可能很有用。

问题

tempAppDomain.Load(assemblyFileBuffer, symbolsFileBuffer); 会将程序集加载到tempAppDomain,但也会加载到执行代码的应用程序域中。您还必须卸载该应用程序域才能删除该文件。不过,您可能不想这样做。

解决方案

您必须执行从应用程序域tempAppDomain 加载程序集的代码。您可以使用tempAppDomain 上的DoCallBack 函数来执行tempAppDomain 中的代码。如果您在那里加载程序集,那么您应该能够在调用 tempAppDomain.Unload() 后删除该文件。

示例

class Program 
{
    private static string assemblyPath = @"C:\Users\wesselm\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\ClassLibrary1.dll";

    static void Main(string[] args)
    {
        AppDomainSetup setup = new AppDomainSetup();
        setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
        var appDomain = AppDomain.CreateDomain("myAppDomain", null, setup);

        // Loads assembly in both application domains.
        appDomain.Load(AssemblyName.GetAssemblyName(assemblyPath));

        // Only loads assembly in one application domain.
        appDomain.DoCallBack(() => AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(assemblyPath)));

        AppDomain.Unload(appDomain);

        File.Delete(assemblyPath);
    }
}

来源

http://msdn.microsoft.com/en-us/library/system.appdomain.docallback.aspx
http://msdn.microsoft.com/en-us/library/36az8x58.aspx
https://stackoverflow.com/a/2475177/210336

【讨论】:

  • 这个答案帮助我解决了一个非常相似的目标。我遇到的唯一问题:我无法将 lambda 用于回调工作负载。我创建了一个扩展 MarshalByRefObject 的小助手类,以创建可序列化的跨 appdomain 对象,这也使我能够从“远程”调用中获得一些结果。
【解决方案2】:

查看这些页面:

http://connect.microsoft.com/VisualStudio/feedback/details/536783/vsip-assembly-file-handles-not-being-released-after-appdomain-unload

http://msdn.microsoft.com/it-it/library/43wc4hhs.aspx

使用 LoaderOptimization.MultiDomainHost 设置新的 AppDomain AppDomainSetup

例如

domainnew = AppDomain.CreateDomain(
    newdomain_name,
    null,
    new AppDomainSetup 
    {
        ApplicationName = newdomain_name,
        ApplicationBase = assembly_directory,
        ConfigurationFile = ConfigurationManager.OpenExeConfiguration(assemblylocation).FilePath,
        LoaderOptimization = LoaderOptimization.MultiDomainHost,
        //http://msdn.microsoft.com/it-it/library/43wc4hhs.aspx
        ShadowCopyFiles = shadowcopy ? "true" : "false",
    });

最好的问候

【讨论】:

  • ShadowCopyFiles = "true" 为我工作...
【解决方案3】:

如果您正在阅读这样的文件:

FileStream assemblyFileStream = new FileStream(tempAssemblyFile, FileMode.Open);

byte[] assemblyFileBuffer = new byte[assemblyFileStream.Length];
assemblyFileStream.Read(assemblyFileBuffer, 0, (int)assemblyFileStream.Length);

如果你这样做,你的问题应该得到解决:

byte[] newAssemblyBuffer = new byte[assemblyFileBuffer.Length];
assemblyFileBuffer.CopyTo(newAssemblyBuffer, 0);

并改变这个:

Assembly projectAssembly = tempAppDomain.Load(newAssemblyFileBuffer, symbolsFileBuffer);

或者,这也应该可以工作,并允许您跳过文件流:

byte[] assemblyFileBUffer = File.ReadAllBytes(tempAssemblyFile);

【讨论】:

    【解决方案4】:

    您必须使用 Wrapper 才能成功卸载您的 AppDomain。 在这里你可以找到一个很好的例子 - http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多