Application_End应该在自动App Pool Recycle上启动吗?

时间:2012-11-14 22:41:54

标签: asp.net iis memory-management

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

我在共享主机中有一个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_OnEndApplication_EndApplication_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]处理程序?
  • 我如何确定造成这些回收的原因?

感谢。

编辑:根据@JaniHyytiäinen的回答

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

游泳池然后不合情理地中止? http响应#2& #3接收(这些是AJAX调用,但我在Fiddler中遇到504错误)? 是否接受了#3的请求,或者只是在新池启动之前才排队? 有没有办法知道内存限制已被击中或将要被击中?

欢迎任何策略。

3 个答案:

答案 0 :(得分:14)

iis中存在应用程序池关闭时间限制。假设这是60秒,并且在共享托管环境中存在应用程序池内存限制。您的应用程序池达到此限制,iis告诉应用程序池完成当前请求的所有工作。如果所有请求在60秒之前完成处理,则application_end将触发,应用程序池将正常关闭。但是,如果60秒仍然处理并且请求仍在处理中,则IIS会感到不安并杀死应用程序池。这次没有application_end会触发。同样,不会触发错误事件处理程序。

答案 1 :(得分: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”修饰符。我已经看到很多情况下反射对私人成员不起作用,所以可能会发挥作用。

另外,尝试将本地/开发应用程序池中的idle timeout设置为低(例如1分钟),然后确保Application_End事件在本地触发。

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

答案 2 :(得分:0)

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

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