案例分析:session丢失及appdomain回收
来源:互联网 发布:urlencode java 编辑:程序博客网 时间:2024/06/05 09:18
原文地址:http://blogs.msdn.com/tess/archive/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles.aspx
版权归原作者所有,转载请注明出处!
案例分析:session丢失及appdomain回收
在进入细节之前,先看两个问题
appdomain回收时发生了什么?
appdomain回收的原因是什么?
asp.net中每一个应用程序都运行于自己的appdomain中,举个例子,假设你有如下的站点结构:
WebSite root
/HrWeb
/EmployeeServices
/FinanceWeb
/SalesWeb
每一个子目录都配置为应用程序,那么asp.net进程中会有如下的appdomain:
System Domain
Shared Domain
Default Domain
Root
HrWeb
EmployeeServices
FinanceWeb
SalesWeb
除了前三个比较特殊之外,其他的每个都包含应用程序相关的数据,包含的具体内容对本文主题来说没什么价值
所有应用程序相关的装配件
一个HttpRuntime对象
一个Cache对象
当appdomain卸载时所有上面所说的都将丢失,这意味着下一次请求到来时所有的装配件都将被重新加载,代码重新JIT,cache以及任何inproc模式的session等都被清空。这会带来很大的性能冲击,可以想象,保证appdomain不频繁回收非常重要.
appdomain为什么会回收
以下任意情况发生,appdomain都会卸载:
1.Machine.Config, Web.Config or Global.asax被修改
2.bin目录或里面的内容被修改
重编译次数(aspx, ascx or asax)达到了配置文件中(machine.config or web.config中的<compilation 3.numRecompilesBeforeAppRestart=/>设置)指定的次数(默认值为15)
4.虚礼目录的路径被修改
5.CAS(Code Access Security:代码访问安全)策略被修改
6.web服务重启
7.应用程序子目录被删除(仅.net2.0),参见Todd的博客:http://blogs.msdn.com/toddca/archive/2006/07/17/668412.aspx
可能漏掉了一些2.0方面的,但我希望上面覆盖了绝大部分场景
我会更多的关注其中的一些问题,尤其是看起来比较普遍的
未知的config或者bin目录更改
你发誓没有人动过这些, 但在开始剖析时(稍后会展示),导致回收的原因正是配置改变
基本上,Dr. Watson.. 等其他的程序动过它们,其他如病毒扫描或者备份软件或索引服务也是常见原因.他们并没有改动文件的内容,但他们会改动文件的属性,足以触发文件改动监视器发出通知。
如果是病毒扫描造成的,你也许应该考虑将文件夹排除在实时扫描范围外,在仔细确认没人可以访问之后可以安装任何杀毒软件到这些目录
中等到重负载时站点更新
场景:有一个10个装配件的应用,需要更新一些项目下的装配件,有一个机制可以让你在运行时更新装配件,在高负载的情况下做更新的话,再想想?
更新10个文件中的7个,假定需要大概7秒,7秒钟重之内有3个请求,那么你会见到如下的情况:
第1秒:a,b装配件更新到新版本- appdomain开始卸载(任何未决的请求将在完全卸载前完成)
第2秒:1号请求到达,加载一个有2个更新文件的appdomain
第3秒:c被更新 --appdomain开始卸载(任何未决的请求必须在卸载之前完成)
第4秒:d被更新
第5秒:2号请求到达,加载一个新的appdomain,包含4个更新的文件以及三个未更新的
第6秒:e,f更新 ----appdomain开始卸载(任何未决的请求必须在卸载之前完成)
第7秒:f更新
第8秒:3号请求到达,一个包含7个更新过文件的的appdomain加载
看到了没,发生了很多不好的事情
首先,总共发生了三次appdomain重启而不是你认为的一次,因为asp.net不知道什么时候会完成更新.
其次,1号请求和2号请求执行的是部分更新的dll,如果dll依赖于其他也需要被更新的dll,就可能会生成一系列错误,你应该已经想到了这种情况
再次:可能会收到"无法访问装配件,因为文件正在被其他进程使用",因为在映射拷贝时dll被锁定了(参见: http://support.microsoft.com/kb/810281)
换言之:在运行状态下不要进行批量更新
那么,难道这个功能没有用么?不,如果希望更新一个dll,上面的任何一种情况都不会发生,如果在低负载或者没有负载的情况批量更新下很可能不会碰到这些问题,但是如果你希望批量更新dll,应该先关闭应用程序
有一个办法可以避免上面的问题,如果你确定一定要在负载下更新,上面提到的KB略叙了这个办法
.net 1.1 引入了两个新的设置项:<httpRuntime waitChangeNotification= /> 、 <httpRuntime maxWaitChangeNotification= />.
waitChangeNotification用于指定在下一个请求触发appdoamin重启时应该等待多少秒,也就是说,第一秒更新了dll,新请求在第三秒到来,waitChangeNotification设置为5,那么需要等到第八秒(首先是1+5=6秒,之后变为3+5)在新请求获得新的appdomain之前,在第二秒的请求会继续在旧的appdomain中被处理(这个时间是滑动的,所以它总是在最后一次更新后等待5秒)
maxWaitChangeNotification用于指定从第一次请求到来之后等待的最大时间.如果我们将其设置为10,在上面描述的情况中,我们在第一秒和第三秒进行了更新,在第8秒waitChangeNotification超时,将仍然会使用一个新的appdomain来处理请求.如果我们设置为6,那么在第七秒就已经加载了新的appdomain,因为此时maxWaitChangeNotification已经超时.所以这是一个绝对过期而不是滑动过期...并且maxWaitChangeNotification and waitChangeNotification中最小的那个来决定是否回收.
在本文中提到的场景,可以设置waitChangeNotification为3,maxWaitChangeNotification=10来避免多次回收
我知道这样解释或许有点混乱,但希望你明白大致意思
在捣鼓这些设置的时候,还有一些重要的事项
如果不设置那么默认为0
maxWaitChangeNotification必须大于等于waitChangeNotification
如果设置值均大于0,在达到超时时间之前,将看不到任何变化,看起来就像设置和dll被缓存了
重编译
一个常见的场景:有一组aspx页面(包含一些显示新闻的项或者其他),后台有一个内容编辑器周期性的更新这些页面.每一次你更新一个aspx页面都必须重新编译,同样是因为asp.net仅仅知道有人更新了这些文件,没办法知道是代码更新还是简单的静态文本更新。
如果你读过我之前的文章你就会知道,在appdomain卸载之前,装配件不会被卸载.并且每次重编译将产生一个新的装配件,有个设置可以限制重新编译的次数,来避免产生过多的装配件(也是为了限制在这上面的内存使用).默认值为15.
如果页面内容需要持续更新,,建议动态从数据库或文件获取内容而不是更新aspx页面文件.或者在HTML页面中用frame作为替代.
如何确认应用被回收?
如果遭遇chahe或者session丢失,基本上赌对了,但为了确认,可以查看ASP.NET v…/Application Restarts计数器.
如何确认appdomain重启的原因?
asp.net 2.0可以用内置的Health Monitoring Events来记录应用程序重启的原因.修改C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/CONFIG目录下的主web.config文件,加入下面的节点:
<add name="Application Lifetime Events Default" eventName="Application Lifetime Events"
provider="EventLogProvider" profile="Default" minInstances="1"
maxLimit="Infinite" minInterval="00:01:00" custom="" />
web.config的更改会产生如下的事件:
Event Type: Information
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
Event ID: 1305
Date: 2006-08-02
Time: 13:33:19
User: N/A
Computer: PRATHER
Description:
Event code: 1002
Event message: Application is shutting down. Reason: Configuration changed.
Event time: 2006-08-02 13:33:19
Event time (UTC): 2006-08-02 11:33:19
Event ID: 6fc2b84de5b74b5ba65b21804d18b7bf
Event sequence: 8
Event occurrence: 1
Event detail code: 50004
Application information:
Application domain: /LM/w3svc/1/ROOT/DebuggerSamples-9-127989919076505325
Trust level: Full
Application Virtual Path: /DebuggerSamples
Application Path: c:/inetpub/wwwroot/DebuggerSamples/
Machine name: PRATHER
Process information:
Process ID: 4876
Process name: w3wp.exe
Account name: NT AUTHORITY/NETWORK SERVICE
Custom event details:
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
可以捕获很多事件,甚至可以撰写自己的event和provider.想得到更多信息以及更多可用的事件,查看下面的文章:http://msdn2.microsoft.com/en-us/library/ms228103.aspx
asp.net 1.1可以使用反射来获得关闭信息(在2.0一样可以实现)
如果对细节不感兴趣仅仅想记录日志,查看scottgu的博客
如果希望知道所有的细节,下面告诉你怎么做
正如之前提到的:每个域拥有一个 HttpRuntime 对象
0:014> !do 0x04f6f324
Name: System.Web.HttpRuntime
MethodTable 0x00e39df4
EEClass 0x0b608028
Size 116(0x74) bytes
GC Generation: 2
mdToken: 0x02000078 (c:/winnt/assembly/gac/system.web/1.0.5000.0__b03f5f7f11d50a3a/system.web.dll)
FieldDesc*: 0x00e3955c
MT Field Offset Type Attr Value Name
0x00e39df4 0x4000680 0x4 CLASS instance 0x00000000 _namedPermissionSet
0x00e39df4 0x4000681 0x8 CLASS instance 0x01031904 _fcm
0x00e39df4 0x4000682 0xc CLASS instance 0x01031b64 _cache
0x00e39df4 0x4000683 0x54 System.Boolean instance 0 _isOnUNCShare
0x00e39df4 0x4000684 0x10 CLASS instance 0x01033c88 _profiler
0x00e39df4 0x4000685 0x14 CLASS instance 0x01033ca4 _timeoutManager
0x00e39df4 0x4000686 0x18 CLASS instance 0x0104ded4 _requestQueue
0x00e39df4 0x4000687 0x55 System.Boolean instance 0 _apartmentThreading
0x00e39df4 0x4000688 0x56 System.Boolean instance 0 _beforeFirstRequest
0x00e39df4 0x4000689 0x60 VALUETYPE instance start at 0x010318c8 _firstRequestStartTime
0x00e39df4 0x400068a 0x57 System.Boolean instance 1 _firstRequestCompleted
0x00e39df4 0x400068b 0x58 System.Boolean instance 0 _userForcedShutdown
0x00e39df4 0x400068c 0x59 System.Boolean instance 1 _configInited
0x00e39df4 0x400068d 0x50 System.Int32 instance 0 _activeRequestCount
0x00e39df4 0x400068e 0x5a System.Boolean instance 0 _someBatchCompilationStarted
0x00e39df4 0x400068f 0x5b System.Boolean instance 0 _shutdownInProgress
0x00e39df4 0x4000690 0x1c CLASS instance 0x00000000 _shutDownStack
0x00e39df4 0x4000691 0x20 CLASS instance 0x00000000 _shutDownMessage
0x00e39df4 0x4000692 0x68 VALUETYPE instance start at 0x010318d0 _lastShutdownAttemptTime
0x00e39df4 0x4000693 0x5c System.Boolean instance 1 _enableHeaderChecking
0x00e39df4 0x4000694 0x24 CLASS instance 0x01033e44 _handlerCompletionCallback
0x00e39df4 0x4000695 0x28 CLASS instance 0x01033e60 _asyncEndOfSendCallback
0x00e39df4 0x4000696 0x2c CLASS instance 0x01033e7c _appDomainUnloadallback
0x00e39df4 0x4000697 0x30 CLASS instance 0x00000000 _initializationError
0x00e39df4 0x4000698 0x34 CLASS instance 0x00000000 _appDomainShutdownTimer
0x00e39df4 0x4000699 0x38 CLASS instance 0x0104dc60 _codegenDir
0x00e39df4 0x400069a 0x3c CLASS instance 0x00fc3c48 _appDomainAppId
0x00e39df4 0x400069b 0x40 CLASS instance 0x00fc3ca4 _appDomainAppPath
0x00e39df4 0x400069c 0x44 CLASS instance 0x00fc3d8c _appDomainAppVPath
0x00e39df4 0x400069d 0x48 CLASS instance 0x00fc3d04 _appDomainId
0x00e39df4 0x400069e 0x4c CLASS instance 0x00000000 _resourceManager
0x00e39df4 0x400069f 0x5d System.Boolean instance 0 _debuggingEnabled
0x00e39df4 0x40006a0 0x5e System.Boolean instance 0 _vsDebugAttach
0x00e39df4 0x400067b 0 CLASS shared static _theRuntime
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6f324 0x002165d0:0x04fcb660 <<
0x00e39df4 0x400067c 0x4 CLASS shared static s_autogenKeys
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6ef28 0x002165d0:0x04fcb474 <<
0x00e39df4 0x400067d 0xc System.Boolean shared static s_initialized
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:1 0x002165d0:1 <<
0x00e39df4 0x400067e 0x8 CLASS shared static s_installDirectory
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6f19c 0x002165d0:0x04fcb4d8 <<
0x00e39df4 0x400067f 0x10 System.Boolean shared static s_isapiLoaded
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:1 0x002165d0:1 <<
HttpRuntime对象是静态的,要获得domain内某特定的HttpRuntime对象,可以dump任意HttpRuntime对象然后查看其静态成员_theRuntime...静态成员变量有一点特殊,当使用!do命令时,将得到一个列表而不是直接得到对象地址:
0x00e39df4 0x400067b 0 CLASS shared static _theRuntime
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6f324 0x002165d0:0x04fcb660 <<
列表说明0x0014af68的appdomain还没有初始化,0x0017cd60 的domain地址位于0x04f6f324,0x002165d0位于0x04fcb660
使用!dumpdomain命令可以获得domain的地址:
Domain 3: 0x2165d0
LowFrequencyHeap: 0x00216634
HighFrequencyHeap: 0x0021668c
StubHeap: 0x002166e4
Name: /LM/W3SVC/1/HrWeb-127976921852307107
从前面的列表可以得到一些信息:_debugginEnabled,可以查看debug是否为ture;可以得到cache对象的地址,有意思的是,这个案例的HttpRuntime对象包含了两个成员变量:_shutDownStack和_shutDownMessage在记录事件的时候可以加以利用
在 global.asax 的Application_End方法中,可以加入以下的代码以获得domain内的_theRuntime对象
HttpRuntime runtime = (HttpRuntime) typeof(System.Web.HttpRuntime).InvokeMember("_theRuntime", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
接着获得shutDownMessage and shutDownStack的内容:
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);
剩下的问题就是写日志和等待回收.
结束之前还有一些事情:如果有配置更改的通知,但你不确定谁动了这些文件,建议运行filemon来记录文件访问,这个工具在许多安全性和文件相关的问题上非常有用
版权归原作者所有,转载请注明出处!
案例分析:session丢失及appdomain回收
在进入细节之前,先看两个问题
appdomain回收时发生了什么?
appdomain回收的原因是什么?
asp.net中每一个应用程序都运行于自己的appdomain中,举个例子,假设你有如下的站点结构:
WebSite root
/HrWeb
/EmployeeServices
/FinanceWeb
/SalesWeb
每一个子目录都配置为应用程序,那么asp.net进程中会有如下的appdomain:
System Domain
Shared Domain
Default Domain
Root
HrWeb
EmployeeServices
FinanceWeb
SalesWeb
除了前三个比较特殊之外,其他的每个都包含应用程序相关的数据,包含的具体内容对本文主题来说没什么价值
所有应用程序相关的装配件
一个HttpRuntime对象
一个Cache对象
当appdomain卸载时所有上面所说的都将丢失,这意味着下一次请求到来时所有的装配件都将被重新加载,代码重新JIT,cache以及任何inproc模式的session等都被清空。这会带来很大的性能冲击,可以想象,保证appdomain不频繁回收非常重要.
appdomain为什么会回收
以下任意情况发生,appdomain都会卸载:
1.Machine.Config, Web.Config or Global.asax被修改
2.bin目录或里面的内容被修改
重编译次数(aspx, ascx or asax)达到了配置文件中(machine.config or web.config中的<compilation 3.numRecompilesBeforeAppRestart=/>设置)指定的次数(默认值为15)
4.虚礼目录的路径被修改
5.CAS(Code Access Security:代码访问安全)策略被修改
6.web服务重启
7.应用程序子目录被删除(仅.net2.0),参见Todd的博客:http://blogs.msdn.com/toddca/archive/2006/07/17/668412.aspx
可能漏掉了一些2.0方面的,但我希望上面覆盖了绝大部分场景
我会更多的关注其中的一些问题,尤其是看起来比较普遍的
未知的config或者bin目录更改
你发誓没有人动过这些, 但在开始剖析时(稍后会展示),导致回收的原因正是配置改变
基本上,Dr. Watson.. 等其他的程序动过它们,其他如病毒扫描或者备份软件或索引服务也是常见原因.他们并没有改动文件的内容,但他们会改动文件的属性,足以触发文件改动监视器发出通知。
如果是病毒扫描造成的,你也许应该考虑将文件夹排除在实时扫描范围外,在仔细确认没人可以访问之后可以安装任何杀毒软件到这些目录
中等到重负载时站点更新
场景:有一个10个装配件的应用,需要更新一些项目下的装配件,有一个机制可以让你在运行时更新装配件,在高负载的情况下做更新的话,再想想?
更新10个文件中的7个,假定需要大概7秒,7秒钟重之内有3个请求,那么你会见到如下的情况:
第1秒:a,b装配件更新到新版本- appdomain开始卸载(任何未决的请求将在完全卸载前完成)
第2秒:1号请求到达,加载一个有2个更新文件的appdomain
第3秒:c被更新 --appdomain开始卸载(任何未决的请求必须在卸载之前完成)
第4秒:d被更新
第5秒:2号请求到达,加载一个新的appdomain,包含4个更新的文件以及三个未更新的
第6秒:e,f更新 ----appdomain开始卸载(任何未决的请求必须在卸载之前完成)
第7秒:f更新
第8秒:3号请求到达,一个包含7个更新过文件的的appdomain加载
看到了没,发生了很多不好的事情
首先,总共发生了三次appdomain重启而不是你认为的一次,因为asp.net不知道什么时候会完成更新.
其次,1号请求和2号请求执行的是部分更新的dll,如果dll依赖于其他也需要被更新的dll,就可能会生成一系列错误,你应该已经想到了这种情况
再次:可能会收到"无法访问装配件,因为文件正在被其他进程使用",因为在映射拷贝时dll被锁定了(参见: http://support.microsoft.com/kb/810281)
换言之:在运行状态下不要进行批量更新
那么,难道这个功能没有用么?不,如果希望更新一个dll,上面的任何一种情况都不会发生,如果在低负载或者没有负载的情况批量更新下很可能不会碰到这些问题,但是如果你希望批量更新dll,应该先关闭应用程序
有一个办法可以避免上面的问题,如果你确定一定要在负载下更新,上面提到的KB略叙了这个办法
.net 1.1 引入了两个新的设置项:<httpRuntime waitChangeNotification= /> 、 <httpRuntime maxWaitChangeNotification= />.
waitChangeNotification用于指定在下一个请求触发appdoamin重启时应该等待多少秒,也就是说,第一秒更新了dll,新请求在第三秒到来,waitChangeNotification设置为5,那么需要等到第八秒(首先是1+5=6秒,之后变为3+5)在新请求获得新的appdomain之前,在第二秒的请求会继续在旧的appdomain中被处理(这个时间是滑动的,所以它总是在最后一次更新后等待5秒)
maxWaitChangeNotification用于指定从第一次请求到来之后等待的最大时间.如果我们将其设置为10,在上面描述的情况中,我们在第一秒和第三秒进行了更新,在第8秒waitChangeNotification超时,将仍然会使用一个新的appdomain来处理请求.如果我们设置为6,那么在第七秒就已经加载了新的appdomain,因为此时maxWaitChangeNotification已经超时.所以这是一个绝对过期而不是滑动过期...并且maxWaitChangeNotification and waitChangeNotification中最小的那个来决定是否回收.
在本文中提到的场景,可以设置waitChangeNotification为3,maxWaitChangeNotification=10来避免多次回收
我知道这样解释或许有点混乱,但希望你明白大致意思
在捣鼓这些设置的时候,还有一些重要的事项
如果不设置那么默认为0
maxWaitChangeNotification必须大于等于waitChangeNotification
如果设置值均大于0,在达到超时时间之前,将看不到任何变化,看起来就像设置和dll被缓存了
重编译
一个常见的场景:有一组aspx页面(包含一些显示新闻的项或者其他),后台有一个内容编辑器周期性的更新这些页面.每一次你更新一个aspx页面都必须重新编译,同样是因为asp.net仅仅知道有人更新了这些文件,没办法知道是代码更新还是简单的静态文本更新。
如果你读过我之前的文章你就会知道,在appdomain卸载之前,装配件不会被卸载.并且每次重编译将产生一个新的装配件,有个设置可以限制重新编译的次数,来避免产生过多的装配件(也是为了限制在这上面的内存使用).默认值为15.
如果页面内容需要持续更新,,建议动态从数据库或文件获取内容而不是更新aspx页面文件.或者在HTML页面中用frame作为替代.
如何确认应用被回收?
如果遭遇chahe或者session丢失,基本上赌对了,但为了确认,可以查看ASP.NET v…/Application Restarts计数器.
如何确认appdomain重启的原因?
asp.net 2.0可以用内置的Health Monitoring Events来记录应用程序重启的原因.修改C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/CONFIG目录下的主web.config文件,加入下面的节点:
<add name="Application Lifetime Events Default" eventName="Application Lifetime Events"
provider="EventLogProvider" profile="Default" minInstances="1"
maxLimit="Infinite" minInterval="00:01:00" custom="" />
web.config的更改会产生如下的事件:
Event Type: Information
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
Event ID: 1305
Date: 2006-08-02
Time: 13:33:19
User: N/A
Computer: PRATHER
Description:
Event code: 1002
Event message: Application is shutting down. Reason: Configuration changed.
Event time: 2006-08-02 13:33:19
Event time (UTC): 2006-08-02 11:33:19
Event ID: 6fc2b84de5b74b5ba65b21804d18b7bf
Event sequence: 8
Event occurrence: 1
Event detail code: 50004
Application information:
Application domain: /LM/w3svc/1/ROOT/DebuggerSamples-9-127989919076505325
Trust level: Full
Application Virtual Path: /DebuggerSamples
Application Path: c:/inetpub/wwwroot/DebuggerSamples/
Machine name: PRATHER
Process information:
Process ID: 4876
Process name: w3wp.exe
Account name: NT AUTHORITY/NETWORK SERVICE
Custom event details:
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
可以捕获很多事件,甚至可以撰写自己的event和provider.想得到更多信息以及更多可用的事件,查看下面的文章:http://msdn2.microsoft.com/en-us/library/ms228103.aspx
asp.net 1.1可以使用反射来获得关闭信息(在2.0一样可以实现)
如果对细节不感兴趣仅仅想记录日志,查看scottgu的博客
如果希望知道所有的细节,下面告诉你怎么做
正如之前提到的:每个域拥有一个 HttpRuntime 对象
0:014> !do 0x04f6f324
Name: System.Web.HttpRuntime
MethodTable 0x00e39df4
EEClass 0x0b608028
Size 116(0x74) bytes
GC Generation: 2
mdToken: 0x02000078 (c:/winnt/assembly/gac/system.web/1.0.5000.0__b03f5f7f11d50a3a/system.web.dll)
FieldDesc*: 0x00e3955c
MT Field Offset Type Attr Value Name
0x00e39df4 0x4000680 0x4 CLASS instance 0x00000000 _namedPermissionSet
0x00e39df4 0x4000681 0x8 CLASS instance 0x01031904 _fcm
0x00e39df4 0x4000682 0xc CLASS instance 0x01031b64 _cache
0x00e39df4 0x4000683 0x54 System.Boolean instance 0 _isOnUNCShare
0x00e39df4 0x4000684 0x10 CLASS instance 0x01033c88 _profiler
0x00e39df4 0x4000685 0x14 CLASS instance 0x01033ca4 _timeoutManager
0x00e39df4 0x4000686 0x18 CLASS instance 0x0104ded4 _requestQueue
0x00e39df4 0x4000687 0x55 System.Boolean instance 0 _apartmentThreading
0x00e39df4 0x4000688 0x56 System.Boolean instance 0 _beforeFirstRequest
0x00e39df4 0x4000689 0x60 VALUETYPE instance start at 0x010318c8 _firstRequestStartTime
0x00e39df4 0x400068a 0x57 System.Boolean instance 1 _firstRequestCompleted
0x00e39df4 0x400068b 0x58 System.Boolean instance 0 _userForcedShutdown
0x00e39df4 0x400068c 0x59 System.Boolean instance 1 _configInited
0x00e39df4 0x400068d 0x50 System.Int32 instance 0 _activeRequestCount
0x00e39df4 0x400068e 0x5a System.Boolean instance 0 _someBatchCompilationStarted
0x00e39df4 0x400068f 0x5b System.Boolean instance 0 _shutdownInProgress
0x00e39df4 0x4000690 0x1c CLASS instance 0x00000000 _shutDownStack
0x00e39df4 0x4000691 0x20 CLASS instance 0x00000000 _shutDownMessage
0x00e39df4 0x4000692 0x68 VALUETYPE instance start at 0x010318d0 _lastShutdownAttemptTime
0x00e39df4 0x4000693 0x5c System.Boolean instance 1 _enableHeaderChecking
0x00e39df4 0x4000694 0x24 CLASS instance 0x01033e44 _handlerCompletionCallback
0x00e39df4 0x4000695 0x28 CLASS instance 0x01033e60 _asyncEndOfSendCallback
0x00e39df4 0x4000696 0x2c CLASS instance 0x01033e7c _appDomainUnloadallback
0x00e39df4 0x4000697 0x30 CLASS instance 0x00000000 _initializationError
0x00e39df4 0x4000698 0x34 CLASS instance 0x00000000 _appDomainShutdownTimer
0x00e39df4 0x4000699 0x38 CLASS instance 0x0104dc60 _codegenDir
0x00e39df4 0x400069a 0x3c CLASS instance 0x00fc3c48 _appDomainAppId
0x00e39df4 0x400069b 0x40 CLASS instance 0x00fc3ca4 _appDomainAppPath
0x00e39df4 0x400069c 0x44 CLASS instance 0x00fc3d8c _appDomainAppVPath
0x00e39df4 0x400069d 0x48 CLASS instance 0x00fc3d04 _appDomainId
0x00e39df4 0x400069e 0x4c CLASS instance 0x00000000 _resourceManager
0x00e39df4 0x400069f 0x5d System.Boolean instance 0 _debuggingEnabled
0x00e39df4 0x40006a0 0x5e System.Boolean instance 0 _vsDebugAttach
0x00e39df4 0x400067b 0 CLASS shared static _theRuntime
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6f324 0x002165d0:0x04fcb660 <<
0x00e39df4 0x400067c 0x4 CLASS shared static s_autogenKeys
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6ef28 0x002165d0:0x04fcb474 <<
0x00e39df4 0x400067d 0xc System.Boolean shared static s_initialized
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:1 0x002165d0:1 <<
0x00e39df4 0x400067e 0x8 CLASS shared static s_installDirectory
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6f19c 0x002165d0:0x04fcb4d8 <<
0x00e39df4 0x400067f 0x10 System.Boolean shared static s_isapiLoaded
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:1 0x002165d0:1 <<
HttpRuntime对象是静态的,要获得domain内某特定的HttpRuntime对象,可以dump任意HttpRuntime对象然后查看其静态成员_theRuntime...静态成员变量有一点特殊,当使用!do命令时,将得到一个列表而不是直接得到对象地址:
0x00e39df4 0x400067b 0 CLASS shared static _theRuntime
>> Domain:Value 0x0014af68:NotInit 0x0017cd60:0x04f6f324 0x002165d0:0x04fcb660 <<
列表说明0x0014af68的appdomain还没有初始化,0x0017cd60 的domain地址位于0x04f6f324,0x002165d0位于0x04fcb660
使用!dumpdomain命令可以获得domain的地址:
Domain 3: 0x2165d0
LowFrequencyHeap: 0x00216634
HighFrequencyHeap: 0x0021668c
StubHeap: 0x002166e4
Name: /LM/W3SVC/1/HrWeb-127976921852307107
从前面的列表可以得到一些信息:_debugginEnabled,可以查看debug是否为ture;可以得到cache对象的地址,有意思的是,这个案例的HttpRuntime对象包含了两个成员变量:_shutDownStack和_shutDownMessage在记录事件的时候可以加以利用
在 global.asax 的Application_End方法中,可以加入以下的代码以获得domain内的_theRuntime对象
HttpRuntime runtime = (HttpRuntime) typeof(System.Web.HttpRuntime).InvokeMember("_theRuntime", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
接着获得shutDownMessage and shutDownStack的内容:
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);
剩下的问题就是写日志和等待回收.
结束之前还有一些事情:如果有配置更改的通知,但你不确定谁动了这些文件,建议运行filemon来记录文件访问,这个工具在许多安全性和文件相关的问题上非常有用
- 案例分析:session丢失及appdomain回收
- 心得2--Session简介及案例分析
- session 丢失及解决办法(FRAMESET)
- Https跳到http时session信息丢失的分析及解决方案
- Https跳到http时session信息丢失的分析及解决方案
- Session会话概述及案例
- Session配置以及丢失的原因分析
- Session丢失的原因及解决办法
- Session莫名丢失的原因及解决办法
- Session的散列及过期回收
- java web用户频繁非正常登出系统(session丢失)的原因分析及解决思路
- session 丢失
- Session丢失
- session丢失
- session丢失
- session丢失
- session丢失
- session回收
- 跳伞集训
- 实战VC时间控制函数
- Javascript - Prototype Based Language
- C#(WINFORM)实现模拟POST发送请求登录网站
- C#得到系统进程和结束某个指定的进程
- 案例分析:session丢失及appdomain回收
- C#中利用委托实现多线程跨线程操作
- 重命名域控制器
- 层的隐藏与显示
- 开通了CSDN Blog
- 根据字段内容查找表名
- 4月9日下午去神州数码面试算法答案----求字符串最大公串
- Visual C#常用函数和方法集汇总
- 今天做了一个公司的面试题目C#实现词法分析器