8

我已经阅读了这个这个这个这个以及其他十几个帖子/博客。

我在共享主机中有一个经常回收的 ASP.Net 应用程序。我们使用 NLog 并在 global.asax 中有以下代码

void Application_Start(object sender, EventArgs e) 
{
    NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
    logger.Debug("\r\n\r\nAPPLICATION STARTING\r\n\r\n");
}
protected void Application_OnEnd(Object sender, EventArgs e)
{
    NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
    logger.Debug("\r\n\r\nAPPLICATION_OnEnd\r\n\r\n");
}

void Application_End(object sender, EventArgs e) 
{
        HttpRuntime runtime = (HttpRuntime)typeof(System.Web.HttpRuntime).InvokeMember("_theRuntime", BindingFlags.NonPublic  | BindingFlags.Static  | BindingFlags.GetField,  null,  null,  null);

if (runtime == null)
    return;

string shutDownMessage = (string)runtime.GetType().InvokeMember("_shutDownMessage",  BindingFlags.NonPublic  | BindingFlags.Instance  | BindingFlags.GetField,  null,  runtime,  null);

string shutDownStack = (string)runtime.GetType().InvokeMember("_shutDownStack",   BindingFlags.NonPublic  | BindingFlags.Instance  | BindingFlags.GetField,  null,  runtime,  null);

ApplicationShutdownReason shutdownReason = System.Web.Hosting.HostingEnvironment.ShutdownReason;

NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
logger.Debug(String.Format("\r\n\r\nAPPLICATION END\r\n\r\n_shutDownReason = {2}\r\n\r\n _shutDownMessage = {0}\r\n\r\n_shutDownStack = {1}\r\n\r\n",
                shutDownMessage, shutDownStack, shutdownReason));
}

void Application_Error(object sender, EventArgs e) 
{
    NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
    logger.Debug("\r\n\r\nApplication_Error\r\n\r\n");

}

我们的日志文件中到处都是“APPLICATION STARTING”条目,但在这些自发重启期间,既没有Application_OnEnd, Application_End, 也没有Application_Error被触发。我知道它们正在工作,因为有用于触摸 web.config 或 /bin 文件的条目。我们还运行了内存过载测试,并且可以触发OutOfMemoryException被捕获的Application_Error.

我们正在尝试确定虚拟内存限制是否导致回收。我们在GC.GetTotalMemory(false)整个代码中都添加了,但这适用于所有 .Net,而不仅仅是我们的应用程序池,对吗?我们也试过

var oPerfCounter = new PerformanceCounter();
oPerfCounter.CategoryName = "Process";
oPerfCounter.CounterName = "Virtual Bytes";
oPerfCounter.InstanceName = "iisExpress";
logger.Debug("Virtual Bytes: " + oPerfCounter.RawValue + " bytes");

但没有共享主机的权限。

我已经监视了开发服务器上的应用程序,该应用程序具有相同的请求,这些请求导致在生产中使用 ANTS Memory Profiler 进行回收,并且似乎找不到罪魁祸首。我们还使用 dev 中附加的调试器运行它,以检查衍生线程中可能导致应用程序中止的未捕获异常。

我的问题是:

  • 如何有效监控共享主机中的内存使用情况,以了解我的应用程序在应用程序回收之前消耗了多少?
  • 为什么没有调用 global.asax 中的 Application_[End/OnEnd/Error] 处理程序?
  • 我还能如何确定导致这些回收的原因?

谢谢。

编辑:基于@Jani Hyytiäinen 的回答

场景:线程#1 开始,然后是线程#2。线程 #1 达到内存限制但继续处理。线程#3 开始。线程 #1 完成,但 #2 在 #1 达到内存限制后处理超过 60 秒。

池然后不优雅地中止?#2 和 #3 会收到什么 http 响应(这些是 AJAX 调用,但我在 Fiddler 中收到 504 错误)?
#3 的请求是否被接受,还是只是排队等待新池启动?
有没有办法知道内存限制已经达到或即将达到?

欢迎任何策略。

4

3 回答 3

16

iis 中有应用程序池关闭时间限制。假设它是 60 秒,并且在共享主机环境中存在应用程序池内存限制。您的应用程序池达到此限制,iis 告诉应用程序池完成当前请求的所有工作。如果所有请求在 60 秒之前完成处理,application_end 将触发,应用程序池将优雅地自行关闭。但是,如果 60 秒过去了,请求仍在处理中,IIS 就会感到不安并终止应用程序池。这次没有 application_end 会触发。同样,不会触发任何错误事件处理程序。

于 2012-11-14T23:04:02.230 回答
0

不确定您使用的是哪个版本的 IIS,但在 IIS7.5 上有一堆应用程序池回收事件日志设置,可让您记录应用程序池回收的原因。

在 IIS 中,转到应用程序池并转到相关应用程序池的高级设置。转到回收,有一个名为“生成回收事件日志条目”的子菜单。

于 2013-05-28T07:59:43.243 回答
0

我查看了我的一个正确触发关闭事件的应用程序,这是 Global.asax.cs 中的签名:

protected void Application_End(object sender, EventArgs e)
{
    ApplicationShutdownReason shutdownReason = System.Web.Hosting.HostingEnvironment.ShutdownReason;
    // Write to log
}

我注意到的唯一区别是您的“Application_End”和“Application_Error”方法没有“protected”修饰符。我见过很多情况,反射不适用于私人成员,所以这可能在起作用。

此外,尝试将本地/开发应用程序池上的空闲超时设置为较低(如 1 分钟),然后确保您的 Application_End 事件在本地触发。

请注意,默认情况下,IIS 应用程序池会在 20 分钟无请求后回收,因此如果您的应用程序流量较低,您可能会遇到这种情况。此外,一些共享主机提供商将这个“空闲超时”值更改为更低以节省资源。

于 2012-11-14T22:57:27.557 回答