【问题标题】:IIS application pool recycling and native assembliesIIS 应用程序池回收和本机程序集
【发布时间】:2014-10-07 06:06:26
【问题描述】:

我有一个在 IIS 下运行的应用程序,该应用程序具有三个程序集:托管程序集、混合程序集和本机 dll。 托管程序集公开了一个单例对象 MaS,该对象通过混合单例 MiS (C++/CLI) 包装了本机单例 NaS

问题

当 IIS 回收应用程序池时,托管单例 MaS 似乎消失了,它的程序集从 APPDOMAIN 中卸载,混合的 MiS 也是如此。然而,原生单例NaS 仍然存在并且不会被破坏。这在我的情况下是有问题的,因为当应用程序被回收并再次加载时,托管单例,现在 MaS1 会因为它在内存中找到一个已经存在的本机单例 NaS 而感到困惑。

问题

在应用程序池回收时如何处理本机 dll?他们会被卸载吗?

【问题讨论】:

  • 我不希望非 COM 原生对象被神奇地破坏,因为一些技术上不相关的“管理程序集”在 AppDomain 回收时被卸载。显然,进程内对象将在 AppPool(进程)回收时被销毁......这与你的观察相矛盾,让我完全困惑......
  • @AlexeiLevenkov 完全同意你的看法!我认为将这些邪恶的二进制文件称为程序集是对 .NET 的不尊重。会更新我的帖子。谢谢
  • @AlexeiLevenkov 没错!所有托管对象都被销毁,本地对象保留在内存中并且不会被销毁:(

标签: c# .net iis .net-assembly


【解决方案1】:

Appdomain回收不会卸载appdomain,它会加载一个新的域,后续请求由一个新的appdomain处理。

只有在处理完已接受的请求后,旧的 appdomain 才会卸载。

如果旧的 appdomain 在非托管代码中执行阻塞操作,也有可能无法卸载。

作为一种解决方法,您可以禁用 apppool 回收并配置重叠的工作进程。 单独的工作进程肯定会隔离非托管的 dll 状态。

您可以使用以下代码轻松检查非托管 dll 的状态是否在 appdomains 之间共享:

托管代码:

[DllImport("Win32Library.dll")]
public static extern Int16 inc();

private readonly static DateTime AppDomainStarted = DateTime.UtcNow;

public ActionResult Counter()
{
    return new JsonResult { Data = new { counter = inc(), appDomainId = AppDomain.CurrentDomain.Id, started = AppDomainStarted.ToString() }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}

非托管代码:

extern "C" __declspec(dllexport) short inc();

short inc()
{
    static int counter = 0;
    return counter++;
}

只需重新编译您的 aspnet 代码并刷新浏览器即可查看计数器中的递增结果以及工作进程中的 appdomain id。确保使用 IISExpress 进行调试。

【讨论】:

  • +1。嗯好的,所以当新的应用程序域被加载时,一个新的托管单例被创建而没有它的本机计数器部分,因为它已经在内存中,这是正确的吗?这些应用程序域是否共享所有加载的原生对象,或者每个应用程序域都有自己的一组原生对象?
  • 它在工作进程中的所有应用程序域之间共享。需要回收worker进程重新初始化。
  • 我猜这仅适用于 IIS 配置为将所有后续应用程序域加载到同一进程中,对吧?
  • 默认情况下。您需要检查应用程序池中的可用设置。 Appdomains 会定期回收,并且工作进程会随机生成。通常,出于故障保护原因,工作进程会被回收。
猜你喜欢
  • 2011-09-20
  • 2010-11-12
  • 2011-03-10
  • 1970-01-01
  • 2019-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多