【问题标题】:Referencing an unstable DLL引用不稳定的 DLL
【发布时间】:2023-03-25 16:33:01
【问题描述】:

我们在 .net 项目中引用了第 3 方专有的 CLI DLL。该 DLL 只是其专有 C++ 库的接口。我们的项目是一个 asp.net (MVC4/Web API) 网络应用程序。

C++ 非托管库相当不稳定。有时它会崩溃,例如悬空指针。我们没有办法解决,使用这个库是一流的客户需求。

当应用程序崩溃时,IIS 中的应用程序池不再响应。我们必须重新启动它,这样做需要几分钟(是的,很长!)。

我们希望防止这个不稳定的 DLL 使我们的应用程序崩溃。最好的方法是什么?我们可以将 CLI DLL 保存在单独的 AppDomain 中吗?怎么样?

提前致谢。

【问题讨论】:

  • 你观察到了什么?在一定数量的调用后进程是否挂起?你怀疑不稳定的 DLL 有内存泄漏吗?
  • 内存泄漏直到现在都不是问题。在开发过程中,DLL 有时会因内存访问冲突而使开发服务器崩溃。有时开发服务器会使用约 70% 的 CPU,直到我终止该进程。在 IIS 中部署时,崩溃和 CPU 问题并没有真正发生,但偶尔 IIS 进程停止响应,并且 IIS 重新启动需要很长时间。
  • 您是否尝试过提高 IIS 进程回收率?
  • 这无济于事,因为问题是我们得到了悬空指针 - 回收将有助于解决内存泄漏

标签: asp.net .net iis command-line-interface unmanaged


【解决方案1】:

我认为这个问题的每一个答案都将是某种解决方法。

我的解决方法是不直接与您的 Web 应用程序中的 DLL 交互。

而是将您的请求从 Web 应用程序写入消息队列或 SQL 表。然后,您可以让另一个应用程序(例如 Windows 服务)读取请求、与 DLL 交互,然后将结果写回供您的 Web 应用程序读取。

我并不是说 SQL / 消息队列是正确的方式,我更多的是考虑一般的流程。

【讨论】:

    【解决方案2】:

    我在第三方库中遇到了这个确切的问题,该库访问受保护的内存以与硬件复制保护加密狗进行交互。它在控制台或 winforms 应用程序中运行良好,但在从 IIS 应用程序调用时却像疯了一样崩溃。

    我们尝试了几种不同的方法,其中一些在本页的其他答案中有所提及。但最终,对我们来说最好的解决方案是一项非常古老的技术 - .Net Remoting。我知道——这几天有点皱眉。但它非常适合这种特殊需求。

    不稳定的代码被放置在 Windows 服务应用程序中。 Web 应用程序对该服务进行远程调用,该服务将命令中继到第三方库。

    现在我确信您可以使用 WCF、套接字等来做同样的事情。但是远程处理设置起来又快又容易,而且由于我们只与同一台服务器通信,因此它可以在不打开任何端口的情况下工作。它只是在命名管道上进行对话。

    这确实意味着除了 Web 应用程序之外还要安装第二个服务,但这在我的特定用例中是可以接受的。

    如果您做了类似的事情,而第三方代码实际上使服务崩溃,您可能可以在主应用程序中编写一些代码来恢复它。

    因此,当您需要处理不稳定的代码时,进程边界可能比应用程序域更有用。

    【讨论】:

      【解决方案3】:

      我会先提高IIS进程回收率,可能DLL代码在调用一定次数后失败,或者在进程达到一定内存使用量后。

      您可以在此处找到有关 IIS 7.0 回收选项配置的信息:http://technet.microsoft.com/en-us/library/cc753179(v=ws.10).aspx

      在您的情况下,当您知道应用程序的负载较少时,我会在特定时间回收该过程。并且在经过一定数量的请求(低于默认值)后,大部分时间都尝试“新鲜”处理。

      从某种意义上说,回收过程是优雅的,旧的进程在替换它的进程准备好之前不会终止,因此不会有明显的停机时间。 更多关于回收机制的信息在这里:http://technet.microsoft.com/en-us/library/cc745955.aspx

      如果上述方法不能解决问题,我会将调用包装在我自己的代码中,以管理不稳定的 DLL 执行。

      此代码应该从失败中恢复,例如通过重复失败的调用直到获得结果,如果在多次尝试后仍然不可能,则失败并出现正常错误。

      在内部,可以在衍生线程中调用不稳定的 DLL,甚至代码也可以在您可以使用 Process.Start 启动的新外部可执行文件中。

      最后一个选项开销更大,但它可能是您唯一的选择。有关更多信息,请参阅此 SO 问题:How do you handle a thread that has a hung call?

      【讨论】:

        【解决方案4】:

        我建议以下解决方案。

        1. 用另一个 Web 应用程序包装这个 dll。可以是以下之一。既然你已经用过web api,那就最适合你了。

          1. 简单的 ASMX Web 服务
          2. WCF 服务
          3. Asp.Net MVC - WEB Api 服务
        2. 控制您的 p-invoke 代码,以免出现任何错误?请参阅以下文章。

          1. The Black Art of P/Invoke and Marshaling in .NET
          2. P/Invoke Revisited
        3. 将此应用程序发布到具有不同应用程序池的 IIS。
        4. 使用之前推荐的标准技术。我建议为内存和预定时间配置回收 IIS。
          1. IIS process recycling rate
          2. How to limit the memory used by an application in IIS?

        【讨论】:

        • 我看不出用另一个 Web 应用程序包装对我有什么帮助。 IIS 仍会冻结。
        • 每个应用程序池都是不同的进程。您的主应用程序位于不同的池中,即不同的进程继续工作。
        • 但它无法从其他应用程序的崩溃中恢复,因为进程会卡住
        • 当您调用其他应用程序和其他进程卡住时,您的网络调用将超时。它不会卡住,它与调用无响应或不工作的应用程序相同。
        猜你喜欢
        • 1970-01-01
        • 2011-01-16
        • 1970-01-01
        • 2016-10-24
        • 2016-10-10
        • 2013-01-16
        • 2017-05-11
        • 2018-11-26
        • 2016-10-18
        相关资源
        最近更新 更多