<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Speaking of which... : Performance</title><link>http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx</link><description>Tags: Performance</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Make sure you have an Internet connection when using signed assemblies</title><link>http://blogs.msdn.com/johan/archive/2009/11/12/make-sure-you-have-an-internet-connection-when-using-signed-assemblies.aspx</link><pubDate>Thu, 12 Nov 2009 11:08:22 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9921295</guid><dc:creator>JohanS</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/johan/comments/9921295.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=9921295</wfw:commentRss><description>&lt;p&gt;A customer called in the other day and told me that his web application took a long time to start. My initial thought was (off course) that it was a matter of the classic slow-to start web services I’ve written about earlier.&lt;/p&gt;  &lt;p&gt;(&lt;a title="What to do about the slow startup of web services" href="http://blogs.msdn.com/johan/archive/2008/04/02/what-to-do-about-the-slow-startup-of-web-services.aspx"&gt;What to do about the slow startup of web services&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;As I learned more about his problem I found that this was more than just a simple matter of pre-compilation and keeping your w3wp.exe alive.&lt;/p&gt;  &lt;h1&gt;The Cause&lt;/h1&gt;  &lt;p&gt;The customer was using authenticode signed assemblies in his web application. When that application calls the assembly for the first time it will want to go on-line and check that the certificate is still valid. So, what if this is an internal server with no Internet access? Well, then we have a problem. The process will spend quite some time trying to check the certificate revocation lists. Eventually it will give up, but for my customer this meant that it hung for at least 20 seconds upon startup.&lt;/p&gt;  &lt;h1&gt;The Resolution&lt;/h1&gt;  &lt;p&gt;To resolve this I’d chose one of the following three options:&lt;/p&gt;  &lt;h3&gt;Grant Internet access to the server&lt;/h3&gt;  &lt;p&gt;This is will obviously resolve the problem, but may not always be possible.&lt;/p&gt;  &lt;h3&gt;Review the need for Authenticode signing&lt;/h3&gt;  &lt;p&gt;If you own the assemblies then you might want to consider not using Authenticode signing at all. A Strong Named Assembly might be sufficient. For more information on Strong Named Assemblies and how to create them, please see the following article on MSDN: &lt;a title="How to- Sign an Assembly with a Strong Name" href="http://msdn.microsoft.com/en-us/library/xc31ft41.aspx" target="_blank"&gt;How to: Sign an Assembly with a Strong Name&lt;/a&gt;&lt;/p&gt;  &lt;h3&gt;Disable Signature Verification&lt;/h3&gt;  &lt;p&gt;If all else fails you can disable Signature Verification by adding the following to your machine.config or application.exe.config:&lt;/p&gt;  &lt;div class="SampleCode"&gt;&amp;lt;configuration&amp;gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;runtime&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;generatepublisherevidence enabled=&amp;quot;false&amp;quot; /&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/runtime&amp;gt;     &lt;br /&gt;&amp;lt;/configuration&amp;gt; &lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h1&gt;Identifying the problem using windbg&lt;/h1&gt;  &lt;p&gt;Okay, so if we suspect that this is the problem, how can we verify this?&lt;/p&gt;  &lt;p&gt;I got a memory dump from my customer, so I’ll use that to demonstrate.&lt;/p&gt;  &lt;p&gt;First of all you want to make sure the dump is taken as the application pool hangs upon the first request. Getting a dump right after the problem has occurred will usually do us no good at all. We need to get the dump as the problem is actually ocurring. Having made sure the dump is fine I open up the dump in windbg and load sos.dll. I then use the !aspxpages command to see the pending requests currently on the server. !aspxpages dumps all the HttpContexts found on the heap so we get a list of all currently executing requests, as well as recently finished ones that haven’t been garbage collected yet.&lt;/p&gt;  &lt;div class="DebugSample"&gt;0:000&amp;gt; .load C:\Windows\Microsoft.NET\Framework\v2.0.50727\sos.dll    &lt;br /&gt;0:000&amp;gt; !aspxpages     &lt;br /&gt;Going to dump the HttpContexts found in the heap.     &lt;br /&gt;Loading the heap objects into our cache.     &lt;br /&gt;HttpContext&amp;#160;&amp;#160;&amp;#160; Timeout&amp;#160; Completed&amp;#160;&amp;#160;&amp;#160;&amp;#160; Running&amp;#160; ThreadId ReturnCode&amp;#160;&amp;#160; Verb RequestPath+QueryString     &lt;br /&gt;0x01b41ad4&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; no&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 11 Sec&amp;#160;&amp;#160;&amp;#160;&amp;#160; XXX&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 200&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; /App/     &lt;br /&gt;0x01b75f48&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 110 Sec&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; no&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 11 Sec&amp;#160;&amp;#160;&amp;#160;&amp;#160; XXX&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 401&amp;#160;&amp;#160; GET /App/Default.aspx     &lt;br /&gt;0x01b7eb40&amp;#160;&amp;#160;&amp;#160; 19200 Sec&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; no&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 11 Sec&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#ff0000"&gt;19&lt;/font&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 200&amp;#160;&amp;#160; GET /App/Default.aspx     &lt;br /&gt;Total 3 HttpContext objects &lt;/div&gt;  &lt;p&gt;So, the request on thread 19 is the one we want. As we can see in the ThreadId column it is the only active request. Let’s jump to that thread and investigate what it is doing.&lt;/p&gt;  &lt;div class="DebugSample"&gt;0:000&amp;gt; ~19s    &lt;br /&gt;eax=01510000 ebx=00000000 ecx=03e2d348 edx=776d9a94 esi=03e2d07c edi=00000000     &lt;br /&gt;eip=776d9a94 esp=03e2d034 ebp=03e2d0a4 iopl=0&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; nv up ei ng nz ac pe cy     &lt;br /&gt;cs=001b&amp;#160; ss=0023&amp;#160; ds=0023&amp;#160; es=0023&amp;#160; fs=003b&amp;#160; gs=0000&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; efl=00000297     &lt;br /&gt;ntdll!KiFastSystemCallRet:     &lt;br /&gt;776d9a94 c3&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ret     &lt;br /&gt;0:019&amp;gt; !clrstack     &lt;br /&gt;OS Thread Id: 0x11cc (19)     &lt;br /&gt;ESP&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; EIP&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;03e2eb8c 776d9a94 [PrestubMethodFrame: 03e2eb8c] App.BasePage.&lt;font color="#ff0000"&gt;Page_Load&lt;/font&gt;(System.Object, System.EventArgs)     &lt;br /&gt;03e2eba0 6aada7ff System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)     &lt;br /&gt;03e2ebb0 6c392594 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)     &lt;br /&gt;03e2ebc4 6c38ba84 System.Web.UI.Control.OnLoad(System.EventArgs)     &lt;br /&gt;03e2ebd8 6c38bac3 System.Web.UI.Control.LoadRecursive()     &lt;br /&gt;03e2ebf0 6c387b74 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)     &lt;br /&gt;03e2ed48 6c3877a4 System.Web.UI.Page.ProcessRequest(Boolean, Boolean)     &lt;br /&gt;03e2ed80 6c3876d1 System.Web.UI.Page.ProcessRequest()     &lt;br /&gt;03e2edb8 6c387666 System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext)     &lt;br /&gt;03e2edc4 6c387642 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)     &lt;br /&gt;03e2edd8 012b02a6 ASP.text.ProcessRequest(System.Web.HttpContext)     &lt;br /&gt;03e2ede8 6c38db16 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()     &lt;br /&gt;03e2ee1c 6c36132c System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)     &lt;br /&gt;03e2ee5c 6c95531f System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)     &lt;br /&gt;03e2ee60 6c94b704 [InlinedCallFrame: 03e2ee60]     &lt;br /&gt;03e2ef00 6c93613d System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)     &lt;br /&gt;03e2ef70 6ca0a7a2 System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)     &lt;br /&gt;03e2ef74 6ca0a58f [InlinedCallFrame: 03e2ef74]     &lt;br /&gt;03e2f4c8 01092314 [NDirectMethodFrameStandalone: 03e2f4c8] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)     &lt;br /&gt;03e2f4d8 6ca0a839 System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)     &lt;br /&gt;03e2f55c 6ca0a58f System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)     &lt;br /&gt;03e2f65c 01092314 [ContextTransitionFrame: 03e2f65c] &lt;/div&gt;  &lt;p&gt;So we’re in the Page_Load event of the page in question, but apart from that !clrstack doesn’t tell us much. Let’s take a look at the native callstack instead using the kb-command.&lt;/p&gt;  &lt;div class="DebugSample"&gt;0:019&amp;gt; kb20    &lt;br /&gt;ChildEBP RetAddr&amp;#160; Args to Child&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;03e2d030 776d9254 76adc244 000006d8 00000000 ntdll!KiFastSystemCallRet     &lt;br /&gt;03e2d034 76adc244 000006d8 00000000 03e2d07c ntdll!ZwWaitForSingleObject+0xc     &lt;br /&gt;03e2d0a4 74256247 000006d8 00003a98 00000000 kernel32!&lt;font color="#ff0000"&gt;WaitForSingleObjectEx&lt;/font&gt;+0xbe     &lt;br /&gt;03e2d0d8 74251f7c 0141f2e4 00000002 00202005 cryptnet!CryptRetrieveObjectByUrlWithTimeout+0x1a5     &lt;br /&gt;03e2d1c8 742527a1 0141f2e4 00000002 00202005 cryptnet!CryptRetrieveObjectByUrlW+0xcc     &lt;br /&gt;03e2d268 742591be 00000000 0141f2e4 00000002 cryptnet!RetrieveObjectByUrlValidForSubject+0xa0     &lt;br /&gt;03e2d2c8 74252556 00000000 00000000 00000001 cryptnet!RetrieveTimeValidObjectByUrl+0x15c     &lt;br /&gt;03e2d374 74253fc1 00000082 0141f2d8 00000000 cryptnet!CTVOAgent::GetTimeValidObjectByUrl+0x178     &lt;br /&gt;03e2d45c 74253d98 00000003 018aa590 00000002 cryptnet!CTVOAgent::GetTimeValidObject+0x4a8     &lt;br /&gt;03e2d48c 74253428 00000003 018aa590 018c8220 cryptnet!FreshestCrlFromCrlGetTimeValidObject+0x2d     &lt;br /&gt;03e2d4d0 74259283 00000003 018aa590 018c8220 cryptnet!CryptGetTimeValidObject+0x58     &lt;br /&gt;03e2d54c 74253b1c 00000003 018aa590 018aa590 cryptnet!GetTimeValidCrl+0x2cb     &lt;br /&gt;03e2d590 74253992 018aa590 018c8220 03e2d5c8 cryptnet!GetBaseCrl+0x34     &lt;br /&gt;03e2d63c 757f77d5 00000001 00000001 00000001 cryptnet!&lt;font color="#ff0000"&gt;MicrosoftCertDllVerifyRevocation&lt;/font&gt;+0x163     &lt;br /&gt;03e2d6c8 757f7641 00000001 00000001 00000001 crypt32!I_CryptRemainingMilliseconds+0x2aa     &lt;br /&gt;03e2d74c 757f7a26 00000001 00000001 00000001 crypt32!CertVerifyRevocation+0xd4     &lt;br /&gt;03e2d7f8 757f7838 01899590 00000000 00000000 crypt32!CChainPathObject::CalculateRevocationStatus+0x2d0     &lt;br /&gt;03e2d83c 75806c44 01899590 018c3018 01870fc0 crypt32!CChainPathObject::CalculateAdditionalStatus+0x152     &lt;br /&gt;03e2d904 758069a5 01899590 018aa590 01870fc0 crypt32!CCertChainEngine::CreateChainContextFromPathGraph+0x23e     &lt;br /&gt;03e2d93c 7580be14 018aa590 018aff94 01870fc0 crypt32!CCertChainEngine::GetChainContext+0x46     &lt;br /&gt;03e2d974 749172ba 01421338 018aa590 018aff94 crypt32!CertGetCertificateChain+0x72     &lt;br /&gt;03e2d9dc 749170fc 40000001 00000000 03e2da10 wintrust!_WalkChain+0x1ae     &lt;br /&gt;03e2da18 7491363b 00000000 03e2dbdc 03e2db74 wintrust!WintrustCertificateTrust+0xb9     &lt;br /&gt;03e2db30 7491346c 00000000 03e2dbe4 00000000 wintrust!_VerifyTrust+0x253     &lt;br /&gt;03e2db54 64025b1b 00000000 03e2dbe4 03e2db74 wintrust!WinVerifyTrust+0x50     &lt;br /&gt;03e2dbf8 716b7f4d &lt;font color="#ff0000"&gt;014443f8&lt;/font&gt; 00000000 00000003 mscorsec!&lt;font color="#ff0000"&gt;GetPublisher&lt;/font&gt;+0xe4     &lt;br /&gt;03e2dc50 7145ed3b d60caabc 0188c4a8 00603c48 mscorwks!PEFile::CheckSecurity+0xcb     &lt;br /&gt;03e2dc78 7145ec84 d60caa64 00000000 0188c4a8 mscorwks!PEAssembly::DoLoadSignatureChecks+0x3a     &lt;br /&gt;03e2dca0 7145f0ca 01879f00 00000000 0188c4a8 mscorwks!PEAssembly::PEAssembly+0x109     &lt;br /&gt;03e2df3c 7145f1c5 0188c4a8 00000000 00000000 mscorwks!PEAssembly::DoOpen+0x103     &lt;br /&gt;03e2dfd0 71459062 0188c4a8 00000000 00000000 mscorwks!PEAssembly::Open+0x79     &lt;br /&gt;03e2e134 71456ace 03e2e15c 00000001 00000000 mscorwks!AppDomain::BindAssemblySpec+0x247 &lt;/div&gt;  &lt;p&gt;Here we see that we’re currently trying to check the certificate revocation list. This is done on a separate thread so this thread is currently doing nothing but waiting. Our next step would be to find this thread, but first we can find out the name of the .dll that we’re trying to verify. Look at the first argument to GetPublisher.&lt;/p&gt;  &lt;div class="DebugSample"&gt;0:019&amp;gt; du &lt;font color="#ff0000"&gt;014443f8&lt;/font&gt;     &lt;br /&gt;014443f8&amp;#160; &amp;quot;C:\Windows\Microsoft.NET\Framewo&amp;quot;     &lt;br /&gt;01444438&amp;#160; &amp;quot;rk\v2.0.50727\Temporary ASP.NET &amp;quot;     &lt;br /&gt;01444478&amp;#160; &amp;quot;Files\scstt\57ae16cd\2f8637d5\as&amp;quot;     &lt;br /&gt;014444b8&amp;#160; &amp;quot;sembly\dl3\078f3d05\00fba208_c03&amp;quot;     &lt;br /&gt;014444f8&amp;#160; &amp;quot;6ca01\Microsoft.Practices.Enterp&amp;quot;     &lt;br /&gt;01444538&amp;#160; &amp;quot;riseLibrary.Logging.DLL&amp;quot; &lt;/div&gt;  &lt;p&gt;So it’s a Microsoft .dll that is part of the Enterprise Library. Good to know. Now let’s find the thread that is attempting to retrieve the revocation list by running ~*kb and scanning through the threads until we find this one:&lt;/p&gt;  &lt;div class="DebugSample"&gt;0:021&amp;gt; kb2000    &lt;br /&gt;ChildEBP RetAddr&amp;#160; Args to Child&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;0427d7f8 776d9254 75502283 0000070c 00000001 ntdll!KiFastSystemCallRet     &lt;br /&gt;0427d7fc 75502283 0000070c 00000001 0427d824 ntdll!ZwWaitForSingleObject+0xc     &lt;br /&gt;0427d83c 75501fc8 0000070c 00000714 00000001 mswsock!SockWaitForSingleObject+0x19f     &lt;br /&gt;0427d928 77801693 00000001 00000000 0427d9d0 mswsock!WSPSelect+0x38c     &lt;br /&gt;0427d9a8 72a733e5 00000001 00000000 0427d9d0 ws2_32!select+0x494     &lt;br /&gt;0427e1ec 72a730fd 00000714 0427e210 72a72e88 winhttp!ICSocket::Connect_Start+0x3b0     &lt;br /&gt;0427e1f8 72a72e88 01828250 72a737bc 00000000 winhttp!CFsm_SocketConnect::RunSM+0x42     &lt;br /&gt;0427e210 72a7382b 018b0c60 00000000 00000000 winhttp!CFsm::Run+0x20     &lt;br /&gt;0427e234 72a7467d 01828250 018ccf30 0427e258 winhttp!DoFsm+0x2a     &lt;br /&gt;0427e244 72a74646 0000ea60 00000005 00000020 winhttp!ICSocket::Connect+0x32     &lt;br /&gt;0427e258 72a742b5 0000ea60 00000005 0000ea60 winhttp!ICSocket::Connect+0x13     &lt;br /&gt;0427e2a4 72a74038 01434458 0427e2c8 72a72e88 winhttp!HTTP_REQUEST_HANDLE_OBJECT::OpenConnection_Fsm+0x471     &lt;br /&gt;0427e2b0 72a72e88 01434458 00000000 00000000 winhttp!CFsm_OpenConnection::RunSM+0x37     &lt;br /&gt;0427e2c8 72a7382b 018b0c60 00000000 00000000 winhttp!CFsm::Run+0x20     &lt;br /&gt;0427e2ec 72a74625 01434458 018ccf30 0427e324 winhttp!DoFsm+0x2a     &lt;br /&gt;0427e2fc 72a745bc 00000000 00000000 018b0c60 winhttp!HTTP_REQUEST_HANDLE_OBJECT::OpenConnection+0x2f     &lt;br /&gt;0427e324 72a74526 0141f638 0427e348 72a72e88 winhttp!HTTP_REQUEST_HANDLE_OBJECT::MakeConnection_Fsm+0x9b     &lt;br /&gt;0427e330 72a72e88 0141f638 00000000 00000000 winhttp!CFsm_MakeConnection::RunSM+0x37     &lt;br /&gt;0427e348 72a7382b 018b0c60 00000000 00000000 winhttp!CFsm::Run+0x20     &lt;br /&gt;0427e36c 72a743c1 0141f638 018b0c60 014343c0 winhttp!DoFsm+0x2a     &lt;br /&gt;0427e3ac 72a74339 014343c0 0427e3d0 72a72e88 winhttp!HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm+0x93     &lt;br /&gt;0427e3b8 72a72e88 014343c0 018ccf30 00000000 winhttp!CFsm_SendRequest::RunSM+0x37     &lt;br /&gt;0427e3d0 72a7382b 018b0c60 00000000 00000000 winhttp!CFsm::Run+0x20     &lt;br /&gt;0427e3f4 72a73db0 014343c0 018b0c60 01888820 winhttp!DoFsm+0x2a     &lt;br /&gt;0427e414 72a76f71 00000000 0427e438 72a72e88 winhttp!HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Start+0x2af     &lt;br /&gt;0427e420 72a72e88 01888820 00000001 00000000 winhttp!CFsm_HttpSendRequest::RunSM+0x4c     &lt;br /&gt;0427e438 72a73c3e 018b0c60 00000000 00000000 winhttp!CFsm::Run+0x20     &lt;br /&gt;0427e480 72a73b8b 01888820 018ccf30 00000000 winhttp!StartFsmChain+0xcf     &lt;br /&gt;0427e4c4 72a739d8 018ccf30 00000000 00000000 winhttp!HttpWrapSendRequest+0x18c     &lt;br /&gt;0427e544 742599b4 018ccf30 00000000 00000000 winhttp!WinHttpSendRequest+0x19b     &lt;br /&gt;0427f5e4 74259741 005f7bc0 018ccf30 01898e60 cryptnet!InetSendAuthenticatedRequestAndReceiveResponse+0x56f     &lt;br /&gt;0427f6ec 7425921d 005f7bc0 &lt;font color="#ff0000"&gt;01898e60&lt;/font&gt; 00202005 cryptnet!InetSendReceiveUrlRequest+0x2c8     &lt;br /&gt;0427f724 742523e9 &lt;font color="#ff0000"&gt;01898e60&lt;/font&gt; 00000002 00202005 cryptnet!CInetSynchronousRetriever::RetrieveObjectByUrl+0x5f     &lt;br /&gt;0427f75c 742521a8 &lt;font color="#ff0000"&gt;01898e60&lt;/font&gt; 00000002 00202005 cryptnet!InetRetrieveEncodedObject+0x64     &lt;br /&gt;0427f7b8 74256350 &lt;font color="#ff0000"&gt;01898e60&lt;/font&gt; 00000002 00202005 cryptnet!CObjectRetrievalManager::RetrieveObjectByUrl+0xbb     &lt;br /&gt;0427f810 76ad4911 00000000 0427f85c 776be4b6 cryptnet!CryptRetrieveObjectByUrlWithTimeoutThreadProc+0x67     &lt;br /&gt;0427f81c 776be4b6 01898db0 4e080acf 00000000 kernel32!BaseThreadInitThunk+0xe     &lt;br /&gt;0427f85c 776be489 742562f7 01898db0 ffffffff ntdll!__RtlUserThreadStart+0x23     &lt;br /&gt;0427f874 00000000 742562f7 01898db0 00000000 ntdll!_RtlUserThreadStart+0x1b     &lt;br /&gt;0:021&amp;gt; du &lt;font color="#ff0000"&gt;01898e60&lt;/font&gt;     &lt;br /&gt;01898e60&amp;#160; &amp;quot;http://crl.microsoft.com/pki/crl&amp;quot;     &lt;br /&gt;01898ea0&amp;#160; &amp;quot;/products/CodeSignPCA2.crl&amp;quot; &lt;/div&gt;  &lt;p&gt;This is the thread. To finally verify that it is in fact attempting to download the Certificate Revocation List we can check the value of the first argument to cryptnet!CInetSynchronousRetriever, InetRetrieveEncodedObject and CObjectRetrievalManager::RetrieveObjectByUrl or the second argument to cryptnet!InetSendReceiveUrlRequest as I did above.&lt;/p&gt;  &lt;h1&gt;Conclusion&lt;/h1&gt;  &lt;p&gt;In this case the customer chose to disable Signature Verification completely rather than granting Internet access to the server.&lt;/p&gt;  &lt;p&gt;If you found the windbg-portion of this post hard to understand I can recommend a closer look at my Debugging School (In the menu to the left). Begin with &lt;a title="Getting started with windbg - Part I" href="http://blogs.msdn.com/johan/archive/2007/11/13/getting-started-with-windbg-part-i.aspx"&gt;Getting started with windbg - Part I&lt;/a&gt; and you should be set to go in no time.&lt;/p&gt;  &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9921295" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Worker+Process/default.aspx">Worker Process</category><category domain="http://blogs.msdn.com/johan/archive/tags/Debugging+School/default.aspx">Debugging School</category><category domain="http://blogs.msdn.com/johan/archive/tags/Did+you+know_3F00_/default.aspx">Did you know?</category><category domain="http://blogs.msdn.com/johan/archive/tags/Hangs/default.aspx">Hangs</category></item><item><title>Investigating Locks</title><link>http://blogs.msdn.com/johan/archive/2009/10/09/investigating-locks.aspx</link><pubDate>Fri, 09 Oct 2009 16:49:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9905467</guid><dc:creator>JohanS</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/johan/comments/9905467.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=9905467</wfw:commentRss><description>&lt;p&gt;Consider the following scenario:&lt;/p&gt;  &lt;p&gt;You have an ASP.NET application which intermittently responds sluggishly. As the problem occurs memory usage is about average, as is CPU usage, but still certain pages respond slower and slower. The machine acts just as if it is under heavy load, but judging from the CPU it isn't. In fact CPU usage might even &lt;em&gt;decrease&lt;/em&gt; rather than increase. When trying to access non .NET content such as plain text/html or images you usually find that response times are just as fast as ever.&lt;/p&gt;  &lt;p&gt;When you find that your application has hung in a low CPU state it is usually because of one of the following reasons (in order of likelihood based on my experience) :&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;External resources responding slowly. E.g. a database query or AD lookup is taking a long time to complete and so the application is simply waiting for another server to respond. &lt;/li&gt;    &lt;li&gt;One of the threads of the application has entered a critical section and now several other threads are waiting to enter the same critical section. &lt;/li&gt;    &lt;li&gt;A classic deadlock. Thread A waits for thread B which waits for thread C which waits for thread A. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Quite often you'll see a mixture of items 1 and 2. A thread enters a critical section, calls a remote database, or similar, and all other threads attempting to enter the same critical section will have to nicely stay in line until the struggling database has responded. Still, it is quite possible that the critical section is waiting for a local event to finish, but then you'd usually see a higher CPU load on the machine. (Though not necessarily in the w3wp.exe process.)&lt;/p&gt;  &lt;h1&gt;What are Critical Sections?&lt;/h1&gt;  &lt;p&gt;In case you've forgotten or simply not worked that much with critical sections it might be necessary to refresh your memory on this.&lt;/p&gt;  &lt;p&gt;A Critical Section is a segment of code that you do not want to be executed more than one at a time. In order to ensure this you use the &lt;strong&gt;lock&lt;/strong&gt; keyword to ensure that a certain block of code is able to complete with no interruption from any other threads. To illustrate this I've created the following code sample:&lt;/p&gt;  &lt;div class="SampleCode"&gt;   &lt;pre&gt;public class FileIO
{
    private static object myLock = new object();

	public FileIO()
	{
	}

    public string performLockOperation()
    {
        string strResult = &amp;quot;The Lock Operation started on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        lock (myLock)
        {
            // Let the thread sleep for 10 seconds
            // This way we simulate a File IO operation that takes some time to complete.
            System.Threading.Thread.Sleep(10000);
        }
        strResult += &amp;quot; and ended on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        return strResult;
    }

    public string performNoLockOperation()
    {
        string strResult = &amp;quot;The No Lock Operation started on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        System.Threading.Thread.Sleep(10000);
        strResult += &amp;quot; and ended on &amp;quot; + System.DateTime.Now.ToLongTimeString();
        return strResult;
    }

}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Let's take a quick look at the parts of this class that I've written, called FileIO:&lt;/p&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h2&gt;myLock&lt;/h2&gt;

&lt;p&gt;The class has a static variable called myLock that I will be using to identify the lock I'm about to create. This is why the variable is static. Otherwise I'd be creating new locks for each instance of the FileIO class leaving the lock operation completely redundant. Now that I use a static variable the lock spans all instances of the FileIO class.&lt;/p&gt;

&lt;h2&gt;constructor&lt;/h2&gt;

&lt;p&gt;The constructor is empty. Move along. Nothing to see here.&lt;/p&gt;

&lt;h2&gt;performLockOperation&lt;/h2&gt;

&lt;p&gt;This is the most interesting part of the class. It is the function we'll be using to actually reproduce the potential problems. The function returns a string which will contain information about when the call to the function was made and when it completed. We store this data in a string called strResult which we will eventually be returning as the result of the function call.&lt;/p&gt;

&lt;p&gt;Having declared this variable and put the initial time of the function call in it we then create our lock. This is simply done with the following syntax:&lt;/p&gt;

&lt;div class="SampleCode"&gt;
  &lt;pre&gt;lock (object)
{
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Any code within this block will first make sure that there is not already a lock taken on this object. If there is, then they will pause execution and wait for the lock to become available before continuing execution.&lt;/p&gt;

&lt;p&gt;Inside our lock we then simulate a slow File IO operation by letting the thread sleep for 10 seconds.&lt;/p&gt;

&lt;p&gt;After that we append the current time to the result and return it.&lt;/p&gt;

&lt;h2&gt;performNoLockOperation&lt;/h2&gt;

&lt;p&gt;This function is identical to the previous one, except this time we do not have a critical section. This function is included just for comparison.&lt;/p&gt;

&lt;h1&gt;The potential problem&lt;/h1&gt;

&lt;p&gt;Now, let's get down to business. If we have a web page that makes a call to the performLockOperation-function and that page is requested at the same time by four different clients. What would be the response times?&lt;/p&gt;

&lt;p&gt;The answer is 10, 20, 30 &amp;amp; 40 seconds.&lt;/p&gt;

&lt;p&gt;Here's why:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The thread handling the first request enters the critical section, effectively locking it for everyone else. When it is complete 10 seconds have passed due to the Sleep-call. &lt;/li&gt;

  &lt;li&gt;One of the other threads enters the critical section once the first request is finished. It has already waited for 10 seconds, and the thread will now sleep for an additional 10 seconds. &lt;/li&gt;

  &lt;li&gt;As the second thread finishes one of the remaining two enters the critical section. It has now waited for 20 seconds and will sleep for an additional 10. &lt;/li&gt;

  &lt;li&gt;The final request is able to enter the critical section after having waited for 30 seconds. Once it is complete 40 seconds have passed. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we'd been using the performNoLockOperation instead then all requests would have responded after 10 seconds.&lt;/p&gt;

&lt;p&gt;Now, I know that 10 seconds is an exceptionally long time to let the thread sleep, but this was all for illustration purposes. Imagine instead that the sleeping time was 1 second and the number of requests was 200...&lt;/p&gt;

&lt;h1&gt;&lt;/h1&gt;

&lt;h1&gt;Troubleshooting this issue&lt;/h1&gt;

&lt;p&gt;Okay, so what would it look like when this problem occurs? Let's have a look. If you haven't looked at my posts on getting started with Windbg, then I suggest reading them before continuing. (&lt;a href="http://blogs.msdn.com/johan/archive/2007/11/13/getting-started-with-windbg-part-i.aspx"&gt;Part I&lt;/a&gt; &amp;amp; &lt;a href="http://blogs.msdn.com/johan/archive/2008/05/28/powershell-an-introduction-part-ii.aspx"&gt;Part II&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;First of all I fire up WinDbg, then I attach to the w3wp.exe. I then use &amp;quot;~*e!clrstack&amp;quot; to look at the managed threads of the w3wp.exe application. Here is a snippet of what I get:&lt;/p&gt;

&lt;div class="DebugSample"&gt;
  &lt;pre&gt;OS Thread Id: 0xce0 (24)
Child-SP         RetAddr          Call Site
000000000447e0f0 000007ff001e13d2 FileIO.performLockOperation()
000000000447e170 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
000000000447e1b0 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000447e1e0 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
000000000447e210 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
000000000447e250 000007fee79498ac System.Web.UI.Control.LoadRecursive()
000000000447e2a0 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
000000000447e370 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
000000000447e3d0 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
000000000447e430 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
000000000447e490 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
000000000447e4c0 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
000000000447e570 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
000000000447e610 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
000000000447e7a0 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
000000000447e7f0 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
000000000447e910 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000447ea80 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000447eae0 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
000000000447f310 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
000000000447f3f0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000447f560 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000447f5c0 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
OS Thread Id: 0x15ec (25)
Unable to walk the managed stack. The current thread is likely not a 
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x1958 (26)
Child-SP         RetAddr          Call Site
0000000004c1dd10 000007ff001e13d2 FileIO.performLockOperation()
0000000004c1dd90 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
0000000004c1ddd0 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
0000000004c1de00 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
0000000004c1de30 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
0000000004c1de70 000007fee79498ac System.Web.UI.Control.LoadRecursive()
0000000004c1dec0 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
0000000004c1df90 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
0000000004c1dff0 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
0000000004c1e050 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
0000000004c1e0b0 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
0000000004c1e0e0 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
0000000004c1e190 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
0000000004c1e230 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
0000000004c1e3c0 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
0000000004c1e410 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
0000000004c1e530 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1e6a0 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1e700 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
0000000004c1ef30 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
0000000004c1f010 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1f180 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004c1f1e0 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
OS Thread Id: 0x1e28 (27)
Child-SP         RetAddr          Call Site
000000000492dcf0 000007ff001e13d2 FileIO.performLockOperation()
000000000492dd70 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
000000000492ddb0 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000492dde0 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
000000000492de10 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
000000000492de50 000007fee79498ac System.Web.UI.Control.LoadRecursive()
000000000492dea0 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
000000000492df70 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
000000000492dfd0 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
000000000492e030 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
000000000492e090 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
000000000492e0c0 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
000000000492e170 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
000000000492e210 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
000000000492e3a0 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
000000000492e3f0 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
000000000492e510 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000492e680 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000492e6e0 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
000000000492ef10 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
000000000492eff0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000000492f160 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000000492f1c0 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
OS Thread Id: 0x1c38 (28)
Child-SP         RetAddr          Call Site
0000000004d0e0b0 000007ff001e13d2 FileIO.performLockOperation()
0000000004d0e130 000007feee323ec9 _Default.Page_Load(System.Object, System.EventArgs)
0000000004d0e170 000007fee7956aea System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
0000000004d0e1a0 000007fee794d2c4 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
0000000004d0e1d0 000007fee794d322 System.Web.UI.Control.OnLoad(System.EventArgs)
0000000004d0e210 000007fee79498ac System.Web.UI.Control.LoadRecursive()
0000000004d0e260 000007fee7948db0 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
0000000004d0e330 000007fee7948cdb System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
0000000004d0e390 000007fee7948c70 System.Web.UI.Page.ProcessRequest()
0000000004d0e3f0 000007ff001e0c09 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
0000000004d0e450 000007fee7950117 ASP.default_aspx.ProcessRequest(System.Web.HttpContext)
0000000004d0e480 000007fee791449b System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
0000000004d0e530 000007fee7ffbd41 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
0000000004d0e5d0 000007fee7fed132 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
0000000004d0e760 000007fee7fcf599 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
0000000004d0e7b0 000007fee80f5344 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
0000000004d0e8d0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0ea40 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0eaa0 000007fef72701ea DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32)
0000000004d0f2d0 000007fee80f5424 DomainNeutralILStubClass.IL_STUB(IntPtr, System.Web.RequestNotificationStatus ByRef)
0000000004d0f3b0 000007fee80f65bb System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0f520 000007fee80f4994 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000000004d0f580 000007fef727043b DomainNeutralILStubClass.IL_STUB(Int64, Int64, Int64, Int32&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So, what does this tell us?&lt;/p&gt;

&lt;p&gt;Well, obviously we have four threads that call my function FileIO.performLockOperation() from Page_Load.&lt;/p&gt;

&lt;p&gt;Please note that we don't have any additional callstack, and since the performLockOperation-function was named by me it could just as well have been named &amp;quot;foo&amp;quot;. In order to find out that these threads are actually waiting for a lock we need to look at the native callstack using the kb-command. Let's take a look at thread 24: &lt;/p&gt;

&lt;div class="DebugSample"&gt;
  &lt;pre&gt;0:029&amp;gt; ~24kb
ntdll!NtDelayExecution+0xa
kernel32!SleepEx+0x84
mscorwks!EESleepEx+0x2d
mscorwks!Thread::UserSleep+0x71
mscorwks!&lt;font color="#ff0000"&gt;ThreadNative::Sleep&lt;/font&gt;+0xf9
App_Code_tvh3usvo!&lt;font color="#ff0000"&gt;FileIO.performLockOperation&lt;/font&gt;()+0x8a
App_Web_uywrbugj!_Default.Page_Load(System.Object, System.EventArgs)+0x32
System_Web_RegularExpressions_ni!System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)+0x19
System_Web_ni!System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)+0x2a
System_Web_ni!System.Web.UI.Control.OnLoad(System.EventArgs)+0x84
System_Web_ni!System.Web.UI.Control.LoadRecursive()+0x42
System_Web_ni!System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)+0x97c
System_Web_ni!System.Web.UI.Page.ProcessRequest(Boolean, Boolean)+0xa0
System_Web_ni!System.Web.UI.Page.ProcessRequest()+0x5b
System_Web_ni!System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)+0xf0
App_Web_uywrbugj!ASP.default_aspx.ProcessRequest(System.Web.HttpContext)+0x9
System_Web_ni!System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+0x257
System_Web_ni!System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)+0xab
System_Web_ni!System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)+0x501
System_Web_ni!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)+0x72&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Apparently we entered FileIO.performLockOperation, and then called sleep, (which is what we're doing in this repro in order to simulate a slow IO operation.) So, what do the other threads look like? Here's thread 26:&lt;/p&gt;

&lt;div class="DebugSample"&gt;
  &lt;pre&gt;0:029&amp;gt; ~26kb
ntdll!ZwWaitForMultipleObjects+0xa
kernel32!WaitForMultipleObjectsEx+0x10b
mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0xc1
mscorwks!Thread::DoAppropriateAptStateWait+0x41
mscorwks!Thread::DoAppropriateWaitWorker+0x191
mscorwks!Thread::DoAppropriateWait+0x5c
mscorwks!&lt;font color="#ff0000"&gt;CLREvent::WaitEx&lt;/font&gt;+0xbe
mscorwks!AwareLock::EnterEpilog+0xc9
mscorwks!AwareLock::Enter+0x72
mscorwks!AwareLock::Contention+0x1fb
mscorwks!JITutil_MonContention+0xdf
App_Code_tvh3usvo!&lt;font color="#ff0000"&gt;FileIO.performLockOperation&lt;/font&gt;()+0x7f
App_Web_uywrbugj!_Default.Page_Load(System.Object, System.EventArgs)+0x32
System_Web_RegularExpressions_ni!System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)+0x19
System_Web_ni!System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)+0x2a
System_Web_ni!System.Web.UI.Control.OnLoad(System.EventArgs)+0x84
System_Web_ni!System.Web.UI.Control.LoadRecursive()+0x42
System_Web_ni!System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)+0x97c
System_Web_ni!System.Web.UI.Page.ProcessRequest(Boolean, Boolean)+0xa0
System_Web_ni!System.Web.UI.Page.ProcessRequest()+0x5b&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This is one of the threads waiting for the critical section. It then found that it was unable to get a lock and so began waiting for the critical section on thread 24 to end.&lt;/p&gt;

&lt;h1&gt;Resolving the problem&lt;/h1&gt;

&lt;p&gt;This is the tricky part. There is no quick-fix for this. We can use the debugger to identify the bottleneck, but after that we'll need to review our design in order to get this working smoothly. A couple of generic things to try would be the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Review what you're doing inside the critical section. Is it really necessary to perform all of the operations you're doing, or would it be possible to do some/all of them outside the scope of the critical section?&lt;/li&gt;

  &lt;li&gt;Identify the reason for the lock taking so much time. Can it be resolved by load-balancing or clustering the resource we're waiting for?&lt;/li&gt;

  &lt;li&gt;If we're waiting for another server, make sure the physical infrastructure is okay. Are network response times within the expected parameters or do you need to fix your wiring, router, etc?&lt;/li&gt;

  &lt;li&gt;Are &lt;em&gt;all &lt;/em&gt;calls to the critical section taking the same amount of time, or are there certain calls that take an &lt;em&gt;exceptional&lt;/em&gt; amount of time? Perhaps most calls to the function are just fine, but intermittently a call comes along that tries to get &lt;em&gt;everything &lt;/em&gt;from the AD, database, etc. In order to investigate this I'd use the commands outlined in &lt;a href="http://blogs.msdn.com/johan/archive/2007/11/26/getting-started-with-windbg-part-ii.aspx"&gt;Getting started with windbg -part II&lt;/a&gt;. Identify the thread owning the lock and investigate the callstack and stack objects using !clrstack and !dso. Use !dso and !do to query the stack objects and try to find the SQL query or AD query that is causing the thread to take such a long time to finish. Is the query significantly different from the ones waiting to execute, then this is most likely our culprit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Post Script&lt;/h1&gt;

&lt;p&gt;A quick thought on locks and their limits:&lt;/p&gt;

&lt;p&gt;Locks do not scale well. A lock can only be made within a specific process, so if you're using a web farm, or in any other way more than one w3wp.exe, then you will not be able to lock &lt;em&gt;all &lt;/em&gt;processes. In other words. Server 1 can get a lock, and so can Server 2. Both will happily execute their code independent of each other. For products such as SQL server you'd deal with this in your SQL query, but if you're performing other operations, such as File IO you might have to work around this by using the same approach as Ms Word. Create a lock file in a shared space, and before you enter your critical section you simply check if the file exists:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You are entering your critical section. Look for lock file in shared location&lt;/li&gt;

  &lt;li&gt;If file exists, then wait&lt;/li&gt;

  &lt;li&gt;If/when file doesn't/no longer exist, create file and enter critical section&lt;/li&gt;

  &lt;li&gt;Make sure you have &lt;em&gt;solid&lt;/em&gt; exception handling within the critical section so that you under no circumstances leave the critical section without removing the lock file.&lt;/li&gt;

  &lt;li&gt;When done, remove lock file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9905467" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/WinDbg/default.aspx">WinDbg</category><category domain="http://blogs.msdn.com/johan/archive/tags/Debugging+School/default.aspx">Debugging School</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://blogs.msdn.com/johan/archive/tags/Hangs/default.aspx">Hangs</category></item><item><title>Why doesn’t the GC kick in when the worker process is inactive?</title><link>http://blogs.msdn.com/johan/archive/2008/05/13/why-doesn-t-the-gc-kick-in-when-the-worker-process-is-inactive.aspx</link><pubDate>Tue, 13 May 2008 16:39:48 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8500269</guid><dc:creator>JohanS</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/johan/comments/8500269.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=8500269</wfw:commentRss><description>&lt;p&gt; &lt;p&gt;I got the following question in my &lt;a href="http://blogs.msdn.com/johan/archive/2007/11/13/getting-started-with-windbg-part-i.aspx"&gt;Getting started with windbg&lt;/a&gt; – post and I thought it might be worth posting the replies in a separate article:&lt;/p&gt; &lt;p&gt;&lt;em&gt;Hi Johan,&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;about those threads with an ID of XXXX, should they go away after certain amount of idle time like 2 minutes? I am trouble shooting an application while the application should sit idle (because of no stimulation), however it is still using quite some CPU time and and threadpool threads, where it should not. So I created an adplus dump when it is sitting idle, and I found that there are many threads with ID XXXX, and I created a dump file again after 15 minutes, again, it still have the exact same XXXX threads. All those threads are completion port threads, and I wonder why they did not get recycled?&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Also, when doing a '~*e !clrstack', most of the worker threads and completion port threads are showing "Failed to start stack walk: 80004005". Is there a way to show the stack for those threads, because those are the threads I am interested in.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Thank you!&lt;/em&gt;&lt;/p&gt; &lt;hr&gt;  &lt;p&gt;The GC will be triggered when you’re allocating memory. If your application is inactive, then so is the Garbage Collector. Even if you’re making a few, random allocations they still may not be enough to trigger a GC, so this is not at all unexpected.&lt;/p&gt; &lt;p&gt;The “Failed to start stack walk: 80004005”-error is displayed when the thread &lt;em&gt;did &lt;/em&gt;contain a managed stack, but no longer does.&lt;/p&gt; &lt;p&gt;/ Johan &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8500269" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/WinDbg/default.aspx">WinDbg</category><category domain="http://blogs.msdn.com/johan/archive/tags/Managed+Heap/default.aspx">Managed Heap</category><category domain="http://blogs.msdn.com/johan/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/johan/archive/tags/Worker+Process/default.aspx">Worker Process</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>What to do about the slow startup of web services</title><link>http://blogs.msdn.com/johan/archive/2008/04/02/what-to-do-about-the-slow-startup-of-web-services.aspx</link><pubDate>Wed, 02 Apr 2008 18:05:16 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8351640</guid><dc:creator>JohanS</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/johan/comments/8351640.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=8351640</wfw:commentRss><description>&lt;p&gt;Due to the architecture of web services and web applications they can be quite slow to start. For example on my Windows 2003-box the initial localhost-call to a simple “Hello World!”-web service takes approximately 8 seconds, while the next request is more or less immediate.&lt;/p&gt; &lt;h1&gt;Why is this?&lt;/h1&gt; &lt;p&gt;This isn’t news, really. One of the first things we learned in the early beta stages of ASP.NET was that the first request would take a little extra time due to the &lt;em&gt;Just In Time Compilation &lt;/em&gt;(JIT). This was a major change from the classic ASP architecture where everything was interpreted rather than compiled. Upon the first request the .aspx / .asmx file will be compiled (JIT’ed) into Microsoft Immediate Language (MSIL) and the resulting .dll will be moved to it’s proper location.&lt;/p&gt; &lt;p&gt;This compilation will occur every time the application pool starts causing a significantly longer response time on the first request compared to the following requests.&lt;/p&gt; &lt;h2&gt;Run-time performance over startup performance&lt;/h2&gt; &lt;p&gt;It all comes down to prioritizing run-time performance over a quick startup. Which, in my humble opinion, is a sound choice. There are, however, situations where you may feel that this is to your disadvantage. The other day I got a question from a customer who had a web service that was called quite infrequently and to him this meant that with every other request response times would be horrendous, simply because the application got recompiled.&lt;/p&gt; &lt;p&gt;For each case I get I usually do a quick search on the problem description. I don’t really expect to find the solution this way, since I can only assume that the customer has tried this as well. Instead it will likely present me with a list of troubleshooting steps that the customer has already tried as well as possible solutions that &lt;em&gt;didn’t &lt;/em&gt;fit. (Off course I still need to verify this with the customer).&lt;/p&gt; &lt;p&gt;This time I didn’t really need to do this since I was pretty sure what the cause was. Still, I was curious to see how &lt;em&gt;common&lt;/em&gt; this problem was. I honestly didn’t think this was a very common scenario, but my quick search on the web revealed the contrary. The few hits that I quickly browsed through suggested writing an application that would ping the web service in order to keep it alive. I must admit I find this quite inventive, but I really don’t think it’s the best approach. :)&lt;/p&gt; &lt;h1&gt;What to do&lt;/h1&gt; &lt;p&gt;So, what is to be done about this? Well, I’ve already mentioned that there are better solutions than pinging the web service. As I told my customer there are basically two good options:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Precompile the assemblies  &lt;li&gt;Change the settings for automatic recycling on the worker process&lt;/li&gt;&lt;/ol&gt; &lt;h2&gt;Precompiling the assemblies&lt;/h2&gt; &lt;p&gt;There is a nice little tool called Native Image Generator. (ngen.exe) It will compile the assembly into native images and installs them into the native image cache. The syntax is pretty straight-forward: &lt;span class="InlineCode"&gt;ngen.exe install [assembly]&lt;/span&gt; The problem is that once you’ve changed the assembly you’d have to precompile it again making updates a bit tedious.&lt;/p&gt; &lt;p&gt;There is also a service-version of the ngen called the Native Image Service. More information about ngen can be found at &lt;a title="http://msdn2.microsoft.com/sv-se/magazine/cc163808(en-us).aspx" href="http://msdn2.microsoft.com/sv-se/magazine/cc163808(en-us).aspx"&gt;http://msdn2.microsoft.com/sv-se/magazine/cc163808(en-us).aspx&lt;/a&gt;&lt;/p&gt; &lt;h2&gt;Changing the recycling settings&lt;/h2&gt; &lt;p&gt;The reason why my customer was experiencing this problem was because his application pool would time out and recycle itself due to the default settings in the IIS manager. By default the worker process will recycle after 20 minutes of inactivity, so if no one has pinged your application in that time the next request will cause the application to recompile, resulting in a longer response time. By tweaking this setting in the IIS manager to something more suitable to the current rate of requests, like 40 minutes or maybe even 60 he should also be able to find a nice balance. Actually, considering the low load it would probably be a good idea to turn this setting off completely. Here’s how:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Open up IIS Manager&lt;/li&gt; &lt;li&gt;Locate the Application Pool in question&lt;/li&gt; &lt;li&gt;Right-click it and select “Properties”&lt;/li&gt; &lt;li&gt;Go to the “Performance”-tab&lt;/li&gt; &lt;li&gt;Change, or disable the “Idle timeout” setting&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;img src="http://blogs.msdn.com/photos/johan/images/8351583/original.aspx"&gt; &lt;/p&gt; &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8351640" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Misc/default.aspx">Misc</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://blogs.msdn.com/johan/archive/tags/Web+Services/default.aspx">Web Services</category></item><item><title>Monitoring Application Pool and Application Restarts</title><link>http://blogs.msdn.com/johan/archive/2008/02/18/monitoring-application-pool-and-application-restarts.aspx</link><pubDate>Mon, 18 Feb 2008 17:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7774295</guid><dc:creator>JohanS</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/johan/comments/7774295.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=7774295</wfw:commentRss><description>&lt;P&gt;This morning I found the following in my inbox:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;I had set my web servers running on IIS 6 to recycle if they hit 700 MB (Maximum used Memory).&lt;BR&gt;&lt;/EM&gt;&lt;EM&gt;Can I run a report to know how many times per day or week the W3WP got recycled.&lt;BR&gt;&lt;/EM&gt;&lt;EM&gt;Any suggestions please.&lt;BR&gt;&lt;BR&gt;&lt;/EM&gt;&lt;EM&gt;Thanks in anticipation&lt;/EM&gt;&lt;/P&gt;
&lt;HR&gt;

&lt;P&gt;The quick answer to your question is to use performance monitor:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Start performance monitor 
&lt;LI&gt;Add a new counter 
&lt;LI&gt;Performance object: "ASP.NET v[n]" 
&lt;LI&gt;Counter: "Worker Process Restarts"&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;So, there's the answer. But while we're on the subject I'd like to mention &lt;EM&gt;application &lt;/EM&gt;restarts as well.&lt;/P&gt;
&lt;H1&gt;Applications vs. Application pools&lt;/H1&gt;
&lt;P&gt;Application restarts may lead you think that your entire &lt;EM&gt;application pool &lt;/EM&gt;recycled, while in fact it was only one of the applications &lt;EM&gt;hosted &lt;/EM&gt;by the application pool that restarted. If this is getting confusing, then please remember that there's a difference between application pools and application. An application pool will consist of one or several worker processes and may host one or several applications&lt;EM&gt;.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;There are two easy ways of monitoring application restarts:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Using performance monitor again 
&lt;LI&gt;Have ASP.NET write an event to the event log upon shutdown &amp;amp; startup. (Requires ASP.NET 2.0 or later)&lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;Performance monitor&lt;/H2&gt;
&lt;P&gt;This is probably the easiest, though you won't get too much additional information other than the fact that an application restart occurred. Here's what you do:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Start performance monitor 
&lt;LI&gt;Add a new counter 
&lt;LI&gt;Performance object: "ASP.NET v[n]" 
&lt;LI&gt;Counter: "Application Restarts"&lt;/LI&gt;&lt;/OL&gt;
&lt;H2&gt;Event log&lt;/H2&gt;
&lt;P&gt;By altering the root web.config you can get an event for every application shutdown and start up. This is a good way to get more detailed information on &lt;EM&gt;why&lt;/EM&gt; the application shut down.&lt;/P&gt;
&lt;P&gt;Open up the root web.config, (located in the &lt;SPAN class=InlineCode&gt;%WinDir%\Microsoft.NET\Framework\v2.0.50727\CONFIG&lt;/SPAN&gt; directory,) locate the healthMonitoring.rules subkey and add the following:&lt;/P&gt;
&lt;DIV class=SampleCode&gt;&amp;lt;add name="Application Lifetime Events Default" eventName="Application Lifetime Events"&lt;BR&gt;provider="EventLogProvider" profile="Default" minInstances="1"&lt;BR&gt;maxLimit="Infinite" minInterval="00:01:00" custom="" /&amp;gt;&lt;/DIV&gt;
&lt;P&gt;Now when the application exited for an application-specific reason you'll get an event like this:&lt;/P&gt;
&lt;DIV class=InlineCode&gt;&lt;PRE&gt;Event code: 1002 
Event message: Application is shutting down. Reason: Configuration changed. 
Event time: 2/14/2008 10:00:41 AM 
Event time (UTC): 2/14/2008 9:00:41 AM 
Event ID: a1314c10a0c84222ae2d870d85308304 
Event sequence: 18 
Event occurrence: 1 
Event detail code: 50004 
 
Application information: 
    Application domain: /LM/w3svc/1/ROOT/Test-1-128474532435626182 
    Trust level: Full 
    Application Virtual Path: /Test
    Application Path: c:\inetpub\wwwroot\Test\ 
    Machine name: JOHAN&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;As you can see the application shut down because the configuration changed. Note that you won't get an event if you manually kill the entire application pool in IIS manager, or similar. One thing that you &lt;EM&gt;will &lt;/EM&gt;get, however, is the following event each and every time the application starts up again:&lt;/P&gt;
&lt;DIV class=InlineCode&gt;&lt;PRE&gt;Event code: 1001 
Event message: Application is starting. 
Event time: 2/14/2008 10:00:47 AM 
Event time (UTC): 2/14/2008 9:00:47 AM 
Event ID: 1f41fd3b17764330ac61804094b0abf0 
Event sequence: 1 
Event occurrence: 1 
Event detail code: 0 
 
Application information: 
    Application domain: /LM/w3svc/1/ROOT/Test-1-128474532435626182 
    Trust level: Full 
    Application Virtual Path: /Test
    Application Path: c:\inetpub\wwwroot\Test\ 
    Machine name: JOHAN&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;So even if the application shut down for a reason that didn't generate an event, (IISReset, idle server, etc.) you'll at least see that for some reason it had to start up again.&lt;/P&gt;
&lt;P&gt;/ Johan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7774295" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Worker+Process/default.aspx">Worker Process</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Exceptions</title><link>http://blogs.msdn.com/johan/archive/2008/01/18/exceptions.aspx</link><pubDate>Fri, 18 Jan 2008 18:50:22 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7150105</guid><dc:creator>JohanS</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/johan/comments/7150105.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=7150105</wfw:commentRss><description>&lt;h1&gt;Introduction&lt;/h1&gt; &lt;p&gt;This was originally intended to be a post on identifying and troubleshooting Exceptions using windbg. As I started writing I thought I should write a little something about exceptions in general, just to begin the post. That little something grew to be quite big and all of a sudden it was by all means worthy of a post of its own. &lt;/p&gt; &lt;p&gt;There are two scenarios that are exceptionally (no pun intended) common in my line of work:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Clients are reporting 2nd chance exceptions displayed on screen with the classic "Server Error"- page.  &lt;li&gt;Performance is generally bad, and when we investigate it turns out that there are tons of exceptions being thrown every second.&lt;/li&gt;&lt;/ol&gt; &lt;h2&gt;What exactly is an exception?&lt;/h2&gt; &lt;p&gt;When it comes to the .NET Framework an exception is a managed object that inherits from the Exception Class. It is usually&amp;nbsp;created when something's gone wrong either in the application or the runtime. The exception contains detailed information about the error that created it such as a friendly error message, the stack trace leading to this exception being created, possible inner exceptions (exceptions that caused the exception) and more. In other words they contain a lot more information than a function simply returning a status code other than 0 if something went wrong. This makes it a lot easier for us to troubleshoot the application.&lt;/p&gt; &lt;p&gt;The downside is that this is resource-consuming. All the information available needs to be gathered and so throwing an exception is a lot more costly than returning an error code.&lt;/p&gt; &lt;h2&gt;Exceptions must be handled&lt;/h2&gt; &lt;p&gt;When an exception is thrown it must be handled one way or another or the application/web request will crash/fail. This is done by setting up a try/catch block. &lt;/p&gt; &lt;div class="SampleCode"&gt;&amp;nbsp;&amp;nbsp; try {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; conn.Close();&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp; catch(Exception ex) {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Something went wrong.&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;/div&gt; &lt;p&gt;If anything goes wrong within the try block, the catch block can now deal with it and act appropriately. It is still up to you to code a suitable reaction to the exception, but the interesting thing is that you &lt;strong&gt;need&lt;/strong&gt; to deal with the problem. If the exception is unattended it will cause the application to crash (winforms) or return a "Server Error"-page (IIS).&lt;/p&gt; &lt;p&gt;This is really good, because this way you will know, one way or the other, that something has gone wrong. Even if you forget to add a try/catch block the exception will still be thrown. This will possibly cause the application to crash, but that's a much better option than continuing execution as if nothing happened.&lt;/p&gt; &lt;h2&gt;Exceptions should be avoided&lt;/h2&gt; &lt;p&gt;This is really important. To throw an exception is costly. Chris Brumme has written an &lt;a href="http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx"&gt;excellent post&lt;/a&gt; on this subject and in it he writes about some&amp;nbsp;of the things that the runtime does&amp;nbsp;when throwing an exception. Such as:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Grab a stack trace by interpreting metadata emitted by the compiler to guide our stack unwind.  &lt;li&gt;Run through a chain of handlers up the stack, calling each handler twice.  &lt;li&gt;Compensate for mismatches between SEH, C++ and managed exceptions.  &lt;li&gt;Allocate a managed Exception instance and run its constructor. Most likely, this involves looking up resources for the various error messages.  &lt;li&gt;Probably take a trip through the OS kernel. Often take a hardware exception.  &lt;li&gt;Notify any attached debuggers, profilers, vectored exception handlers and other interested parties.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Exceptions are there to tell you that something's gone wrong, but since they're quite costly to throw it would be much better if you anticipated them and tried to minimize them.&lt;/p&gt; &lt;p&gt;Why use the following code:&lt;/p&gt; &lt;div class="SampleCode"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void calculateAvg(Int32 X, Int32 Y)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Label1.Text = (X / Y).ToString();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (Exception e)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Label1.Text = "Division by Zero";&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/div&gt; &lt;p&gt;when you can just as well use this:&lt;/p&gt; &lt;div class="SampleCode"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void calculateAvg(Int32 X, Int32 Y)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Y != 0)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Label1.Text = (X / Y).ToString();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Label1.Text = "Division by Zero";&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;/div&gt; &lt;p&gt;As you can see, the first piece of code will throw an exception if Y happens to be zero. And all to no use. Take a look again at all the things we go through when throwing an exception and consider if that is really necessary when all you needed to do was to verify that Y != 0.&lt;/p&gt; &lt;h2&gt;How many exceptions is your application throwing&amp;nbsp;per second?&lt;/h2&gt; &lt;p&gt;In a perfect world you should be able to answer this without hesitation. Anyway, if you honestly have no idea then I suggest you start Performance Monitor, add a counter for &lt;em&gt;.NET CLR Exceptions/# of Exceps Thrown &lt;/em&gt;and run a stress test.&lt;/p&gt; &lt;p&gt;&lt;img src="http://blogs.msdn.com/photos/johan/images/7055183/original.aspx"&gt; &lt;/p&gt; &lt;p&gt;I've come across applications that throw over 150.000 exceptions in less than an hour.&lt;/p&gt; &lt;p&gt;There may also be times when this is actually expected and acceptable. For example, the Response.Redirect command results in a System.Threading.ThreadAbortException. If your application relies heavily on Response.Redirect for some reason, then you needn't worry. If, however, you're not aware of what is causing these exceptions I'd urge you to look into it.&lt;/p&gt; &lt;p&gt;None of us would want to let our systems run with constant red or yellow warnings in the event logs. The least we'd do is check up on them and see what caused them.&lt;/p&gt; &lt;p&gt;Well, having written this little introduction I guess I should now get going on the "&lt;em&gt;real&lt;/em&gt;" post. The one&amp;nbsp;about how to find and troubleshoot those exceptions using Windbg...&lt;/p&gt; &lt;p&gt;Later!&amp;nbsp;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7150105" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Exceptions/default.aspx">Exceptions</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>The KB article every one should know about</title><link>http://blogs.msdn.com/johan/archive/2007/05/23/the-kb-article-every-one-should-know-about.aspx</link><pubDate>Wed, 23 May 2007 18:23:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2817754</guid><dc:creator>JohanS</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/johan/comments/2817754.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=2817754</wfw:commentRss><description>&lt;p&gt;Have you read &lt;a href="http://support.microsoft.com/?kbid=307340"&gt;http://support.microsoft.com/?kbid=307340&lt;/a&gt;? If not, I suggest you do so. If you need convincing or simply want to know why this problem occurs I suggest you keep reading.&lt;/p&gt; &lt;p&gt;The problem described in the article above can cause your application to spike in CPU time, Memory usage or both. This will lead to your application hanging or possibly even crashing. The cause of the problem is&amp;nbsp;one of the most basic operations, and is something that we do very frequently.&lt;/p&gt; &lt;p&gt; &lt;hr&gt;  &lt;p&gt;&lt;/p&gt; &lt;h1&gt;The problem&lt;/h1&gt; &lt;p&gt;The problem in a nutshell is that string concatenation is bad. I don't mean bad as in "You shouldn't eat that extra piece of chocolate". I mean it as in "You really shouldn't put your head in wet concrete". If you've been reading my previous post on &lt;a href="http://blogs.msdn.com/johan/archive/2007/04/20/memory-management-in-the-net-framework.aspx"&gt;memory management&lt;/a&gt;&amp;nbsp;you might be able to figure out why string concatenation could be such a potential hazard. Consider the following scenario:&lt;/p&gt; &lt;p&gt;You're getting ready to go grocery shopping. You take a sheet of paper and a pen and begin writing down what you need to buy. The first item that crosses your mind is milk, so you write it down. Now you remember that you're out of bread as well, so you throw away the first sheet of paper, pick out a new one and write down milk and bread. You then throw away this paper too and write down milk, bread and&amp;nbsp;apples on a third piece of paper. You throw away the third piece of paper and repeat until finally the list is done. If you have 20 items on your list you now have 19 discarded papers lying on the floor waiting for the "garbage collector".&lt;/p&gt; &lt;p&gt;This is exactly how regular string concatenation works in .NET. Every time you concatenate a string the framework needs to allocate a new memory segment, large enough to hold the result of the concatenation and store the string in this new segment. The old segment is flagged as ready for garbage collection and as we all know garbage collection costs CPU and pending garbage collection costs memory.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;A real&amp;nbsp;example&lt;/h1&gt; &lt;p&gt;So if you thought that 19 sheets of paper were a waste consider the following piece of code:&lt;/p&gt; &lt;div class="SampleCode"&gt;private String buildTable()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;String sReturn;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i, j;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;sReturn = "&amp;lt;table&amp;gt;"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (i = 0; i &amp;lt; 35; i++) // Rows&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sReturn += "&amp;lt;tr&amp;gt;"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (j = 0; j &amp;lt; 15; j++) // Columns&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sReturn += "&amp;lt;td&amp;gt;"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sReturn += i.ToString() + " : " + j.ToString();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sReturn += "&amp;lt;/td&amp;gt;"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sReturn += "&amp;lt;/tr&amp;gt;"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;sReturn += "&amp;lt;/table&amp;gt;"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;return sReturn;&lt;br&gt;} &lt;/div&gt; &lt;p&gt;All in all we have 2697 concatenations which means we have 2696 unnecessary allocations. The allocations will be gradually bigger and bigger, so the last ones will be almost as big as the final table. Needless to say this will consume a lot of unnecessary memory.&amp;nbsp;Also, if this table was built for a "real" application it would probably contain a lot more data for each cell, not to mention custom styles and classes. Imagine what would happen when the string goes past the magic &lt;a href="http://blogs.msdn.com/johan/archive/2007/04/20/memory-management-in-the-net-framework.aspx"&gt;85000 bytes barrier&lt;/a&gt; that defines what goes on the large object heap and what doesn't. In a larger scale this would have a &lt;em&gt;severe&lt;/em&gt; impact on performance.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;This is a really weird behavior, how can it be?!&lt;/h1&gt; &lt;p&gt;It's not that odd really. If we extend the grocery shopping analogy a little we can see why there's a logical reason for this: You know that you want to write something down. You have a limited amount of paper, so what do you do? You cut out a piece of paper just large enough for you to write what you need. When you find that you need to add another item to the list you'll have to discard the old piece and cut out a new one. Not very practical, agreed, but you're trying to minimize your paper usage.&lt;/p&gt; &lt;p&gt;As the clever beings that we are we normally make a rough estimate of how big a piece of paper we need and then start writing. The framework, however, has no way of estimating how big a string is going to be. It doesn't know if you're going to concatenate it zero or ten thousand time, so that's something you'll have to estimate yourself.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;So what should I do instead?&lt;/h1&gt; &lt;p&gt;One word: StringBuilder&lt;/p&gt; &lt;p&gt;The StringBuilder class is made especially for this type of operations. When using the StringBuilder class our sample above would look something like this&lt;/p&gt; &lt;div class="SampleCode"&gt;private String buildTableSB()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp; StringBuilder sReturn = new StringBuilder();&lt;br&gt;&amp;nbsp;&amp;nbsp; sReturn.Capacity = 8000; // This is optional, but may be very efficient&lt;br&gt;&amp;nbsp;&amp;nbsp; int i, j;&lt;br&gt;&amp;nbsp;&amp;nbsp; sReturn.Append("&amp;lt;table&amp;gt;");&lt;br&gt;&amp;nbsp;&amp;nbsp; for (i = 0; i &amp;lt; 35; i++) // Rows&lt;br&gt;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; sReturn.Append("&amp;lt;tr&amp;gt;");&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; for (j = 0; j &amp;lt; 15; j++) // Columns&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; sReturn.Append("&amp;lt;td&amp;gt;");&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; sReturn.Append(i.ToString());&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; sReturn.Append(" : ");&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; sReturn.Append(j.ToString());&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; sReturn.Append("&amp;lt;/td&amp;gt;");&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; sReturn.Append("&amp;lt;/tr&amp;gt;");&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp; sReturn.Append("&amp;lt;/table&amp;gt;");&lt;br&gt;&amp;nbsp;&amp;nbsp; return sReturn.ToString;&lt;br&gt;}&lt;/div&gt; &lt;p&gt;The difference in performance for a larger operation is enormous. I highly recommend trying out these samples. Copy the functions to a winforms/webforms application, increase the number of rows to 500 and run both versions. The&amp;nbsp;StringBuilder version will finish&amp;nbsp;within milliseconds, and the "classic" version will not...&amp;nbsp;For additional tidbits, take a look at the GC counter in performance monitor and look at how many GCs you have to make to complete the operation.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Bye for now / Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2817754" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/OutOfMemory/default.aspx">OutOfMemory</category><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Managed+Heap/default.aspx">Managed Heap</category><category domain="http://blogs.msdn.com/johan/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Common reasons why your application pool may unexpectedly recycle</title><link>http://blogs.msdn.com/johan/archive/2007/05/16/common-reasons-why-your-application-pool-may-unexpectedly-recycle.aspx</link><pubDate>Wed, 16 May 2007 11:12:27 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2667825</guid><dc:creator>JohanS</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/johan/comments/2667825.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=2667825</wfw:commentRss><description>&lt;p&gt;If your application crashes, hangs and deadlocks it will cause/require the application pool to recycle in order to be resolved, but sometimes your application pool inexplicably recycles for no obvious reason. This is usually a configuration issue or&amp;nbsp;due to the fact that you're performing&amp;nbsp;file system operations in the application directory.&lt;/p&gt; &lt;p&gt;For the sake of elimination I thought I'd list the most common reasons.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Application pool settings&lt;/h1&gt; &lt;p&gt;If you&amp;nbsp;check the properties for the application pool you'll see a number of settings for recycling the application pool. In IIS6 they are:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Recycle worker processes (in minutes)  &lt;li&gt;Recycle worker process (in requests)  &lt;li&gt;Recycle worker processes at the following times  &lt;li&gt;Maximum virtual memory  &lt;li&gt;Maximum used memory&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;These settings should be pretty self explanatory, but if you want to read more, please take a look at &lt;a href="http://msdn2.microsoft.com/en-us/library/aa720473(VS.71).aspx"&gt;this MSDN article&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;The processModel element of machine.config&lt;/h1&gt; &lt;p&gt;If you're running IIS5 or the IIS5 isolation mode you'll have to look at the processModel element. The Properties you should pay the closest attention to are:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;memoryLimit  &lt;li&gt;requestLimit  &lt;li&gt;timeout&lt;/li&gt;&lt;/ul&gt; &lt;h2&gt;memoryLimit&lt;/h2&gt; &lt;p&gt;The default value of memoryLimit is 60. This value is only of interest if you have fairly little memory on a 32 bit machine. 60 stands for 60% of total system memory. So if you have 1 GB of memory the worker process will automatically restart once it reaches a memory usage of 600 MB. If you have 8 GB, on the other hand, the process would &lt;em&gt;theoretically&lt;/em&gt; restart when it reaches 4,8 GB, but since it is a 32 bit process it will never grow that big. See &lt;a href="http://blogs.msdn.com/johan/archive/2007/04/19/why-adding-more-memory-won-t-resolve-outofmemoryexceptions.aspx"&gt;my post on 32 bit processes&lt;/a&gt;&amp;nbsp;for more information why.&lt;/p&gt; &lt;h2&gt;requestLimit&lt;/h2&gt; &lt;p&gt;This setting is "infinite" by default, but if it is set to 5000 for example, then ASP.NET will launch a new worker process once it's served 5000 requests.&lt;/p&gt; &lt;h2&gt;timeout&lt;/h2&gt; &lt;p&gt;The default timeout is "infinite", but here you can set the lifetime of the worker process. Once the timeout is reached ASP.NET will launch a new worker process, so setting this to "00:05:00" would recycle the application every five minutes.&lt;/p&gt; &lt;h2&gt;Other properties&lt;/h2&gt; &lt;p&gt;There are other properties within the processModel element that will cause your application pool to recycle, like responseDeadlockInterval. But these other settings usually depend on something going wrong or being out of the ordinary to trigger. If you have a deadlock then that's your main concern. Changing the responseDeadlockInterval&amp;nbsp;setting wouldn't do much to resolve the situation. You'd need to deal with the deadlock itself.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Editing and updating&lt;/h1&gt; &lt;p&gt;ASP.NET 2.0 depends on File Change Notifications (FCN) to see if the application has been updated. Depending on the change the application pool will recycle. If you or your application is adding and removing directories to the application folder, then you will be restarting your application pool every time, so be careful with those temporary files.&lt;/p&gt; &lt;p&gt;Altering the following files will also trigger an immediate restart of the application pool:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;web.config  &lt;li&gt;machine.config  &lt;li&gt;global.asax  &lt;li&gt;Anything in the bin directory or it's sub-directories&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Updating the .aspx files, etc.&amp;nbsp;causing a recompile will eventually trigger a restart of the application pool as well. There is a property of the compilation element under system.web that is called numRecompilesBeforeAppRestart. The default value is 20. This means that after 20 recompiles the application pool will recycle.&lt;/p&gt; &lt;h2&gt;A workaround to the sub-directory issue&lt;/h2&gt; &lt;p&gt;If your application really depends on adding and removing sub-directories you can use linkd to create a directory junction. Here's how:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Create a directory you'd like to exclude from the FCN, E.g. c:\inetpub\wwwroot\WebApp\MyDir  &lt;li&gt;Create a separate folder somewhere outside the wwwroot. E.g. c:\MyExcludedDir  &lt;li&gt;use linkd to link the two: linkd c:\inetpub\wwwroot\WebApp\MyDir c:\MyExcludedDir  &lt;li&gt;Any changes made in the c:\inetpub\wwwroot\WebApp\MyDir will actually occur in c:\MyExcludedDir so they will go unnoticed by the&amp;nbsp;FCN.&lt;/li&gt;&lt;/ul&gt; &lt;h1&gt;Is recycling the application pool really that bad?&lt;/h1&gt; &lt;p&gt;You really shouldn't have to recycle the application pool, but if you're dealing with a memory leak in your application and need to buy time to fix it, then by all means recycling the application pool could be a good idea.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;What about session state?&lt;/h1&gt; &lt;p&gt;Well, if you're running in-process session state, then obviously it's going to be reset each and every time the application pool is recycled. If you need to brush up on your state server options, then I recommend taking a look at &lt;a href="http://blogs.msdn.com/johan/archive/2006/11/20/sessionstate-performance.aspx"&gt;this entry&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Later! / Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2667825" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/SessionState/default.aspx">SessionState</category><category domain="http://blogs.msdn.com/johan/archive/tags/Worker+Process/default.aspx">Worker Process</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Finalizers and weak references</title><link>http://blogs.msdn.com/johan/archive/2007/04/26/finalizers-and-weak-references.aspx</link><pubDate>Thu, 26 Apr 2007 17:25:57 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2286964</guid><dc:creator>JohanS</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/johan/comments/2286964.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=2286964</wfw:commentRss><description>&lt;p&gt;What do finalizers and weak references have in common? Well more than you might think&amp;nbsp;actually.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Finalizers&lt;/h1&gt; &lt;p&gt;Finalizers are clean-up code that will be run at the end of an objects life-cycle. You should only release native resources in the finalizer. When you use your object you should not the finalizer cleaning up after you. You're much better off performance-wise by making your object Disposable and making sure that you're actually calling the Dispose method. The finalizers should only be the final fail-safe in case the Dispose call is forgotten.&lt;/p&gt; &lt;p&gt;Having a finalizer means your object is &lt;em&gt;always&lt;/em&gt; promoted at least one generation by the Garbage Collector (GC). Here's why:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;You have an object with a finalizer and the object is no longer referenced  &lt;li&gt;The GC comes to collect the object. It sees that the object has a finalizer. The GC therefore adds the object to the finalizer queue and promotes it one generation on the heap  &lt;li&gt;The finalizer is run, once the finalizer thread is available. (If this takes too long the object might actually be promoted a second time.)  &lt;li&gt;The object is finally garbage collected&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Since you only have one finalizer thread and rely heavily on finalizers you may be creating an unintentional bottleneck.&lt;/p&gt; &lt;h2&gt;So shouldn't I use finalizers?&lt;/h2&gt; &lt;p&gt;Well sure you should. But as I've said before, only regard them as a fail-safe. Make your objects disposable and add a finalizer just in case somebody less skilled than yourself forgets to call the Dispose method. :-)&lt;/p&gt; &lt;hr&gt; &lt;/hr&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Weak References&lt;/h1&gt; &lt;p&gt;A weak reference is different from a strong reference since this reference is disregarded when the GC comes to collect the object, so if there are nothing but weak references remaining for an object when the heap is GC' d the object will be collected. Weak references are generally useful in two ways:&lt;/p&gt; &lt;h2&gt;1. Poor mans cache&lt;/h2&gt; &lt;p&gt;If you have a weak reference to an object, say a dataset that takes some time putting together, then you can still work with that object as long as it hasn't been garbage collected. You would work with the reference as you would with any cached item. First you check if the object still exists, if it does, then you get a strong reference to the object&amp;nbsp;and work with it. If not, then you create a new dataset and and work with that one.&lt;/p&gt; &lt;h2&gt;2. Custom finalizer&lt;/h2&gt; &lt;p&gt;Consider the following scenario. (No, you're not having Déjà Vu. This is the same scenario I described in the finalizers section above.):&lt;/p&gt; &lt;ul&gt; &lt;li&gt;You have an object with a finalizer and the object is no longer referenced  &lt;li&gt;The GC comes to collect the object. It sees that the object has a finalizer. The GC therefore adds the object to the finalizer queue and promotes it one generation on the heap  &lt;li&gt;The finalizer is run, once the finalizer thread is available. (If this takes too long the object might actually be promoted a second time.)  &lt;li&gt;The object is finally garbage collected&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Here's an alternative way of doing the same thing:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;You don't use a finalizer. Instead you have an array of weak references to objects that you occasionally check  &lt;li&gt;When you find that one of the weak references' target&amp;nbsp;is null that means the GC has collected that object  &lt;li&gt;The object has been garbage collected, so now you run your own clean-up code.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Okay, so the second alternative has two obvious benefits compared to the first:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Your object won't be automatically promoted to generation 1 or generation 2.  &lt;li&gt;You won't be depending on the finalizer thread being available to run your clean-up code.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;The ultimate option would off course be to have your object being Disposable, make sure you call the Dispose method and use alternatives one or two as back-ups.&lt;/p&gt; &lt;hr&gt; &lt;/hr&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Long Weak References&lt;/h1&gt; &lt;p&gt;Long weak references will survive the finalizer, so even if your object has been finalized you can still reference it. This may be useful in certain situations, but it can be risky if you're not 100% sure what the finalizer does. Let's say your object performs some kind of file I/O and all file references are closed by the finalizer. If you reference this object using a Long Weak Reference you will have an instance of the object with all I/O functionality disabled. Obviously this could cause all sorts of exceptions if you don't know what you're doing.&lt;/p&gt; &lt;hr&gt; &lt;/hr&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Myths and Facts&lt;/h1&gt; &lt;p&gt;I've previously gotten some positive feedback on the Myth / Fact format, so I thought I'd round this topic off by adding a summary using that format. Here goes:&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Myth:&lt;br&gt;&lt;/strong&gt;You can pretty much do anything in the finalizer.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Fact:&lt;br&gt;&lt;/strong&gt;The only thing you &lt;em&gt;should&lt;/em&gt; do in the finalizer is to release your native resources. The reason why your doing this is because you can never be sure that the person using your object is smart enough to call the Dispose method. If everybody did do that, then we wouldn't need the finalizer at all&lt;/p&gt; &lt;p&gt;&lt;br&gt;&lt;strong&gt;Myth:&lt;/strong&gt;&lt;br&gt;If you have a finalizer you don't need to make your component disposable&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Fact:&lt;/strong&gt;&lt;br&gt;You should &lt;em&gt;always&lt;/em&gt; call the Dispose method of any disposable object. It doesn't matter if all it seems to do is set GC.SuppressFinalize(Me). That is no guarantee that the next version of the object won't do all kinds of stuff in the Dispose method. The rule of thumb is: If it is disposable, dispose it.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;br&gt;Myth:&lt;/strong&gt;&lt;br&gt;Having a finalizer has no impact on performance. When the Garbage Collector (GC) comes to collect it the GC will simply call the Finalize method first and then collect it.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Fact:&lt;br&gt;&lt;/strong&gt;Having a finalizer is a &lt;em&gt;guarantee&lt;/em&gt; that your object will be promoted one generation before it is collected by the GC. When the GC comes across an object with a finalizer that is ready to be collected it puts the object in the finalizer queue, but the object is then moved to the next generation. For more information on this, please see my &lt;a href="http://blogs.msdn.com/johan/archive/2007/04/20/memory-management-in-the-net-framework.aspx"&gt;previous post&lt;/a&gt; on the managed heap, the GC and its generations. You also have only one finalizer thread, so this&amp;nbsp;has&amp;nbsp;bottleneck warning written all over it.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;br&gt;Myth:&lt;br&gt;&lt;/strong&gt;Long Weak References are available as long as the object is in the finalizer queue, but they're released once the&amp;nbsp;Finalize method is called.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Fact:&lt;br&gt;&lt;/strong&gt;Nope. They &lt;em&gt;are&lt;/em&gt; available when they're in the finalizer queue, but they're &lt;em&gt;also&lt;/em&gt; available &lt;em&gt;after&lt;/em&gt; the finalizer has been called. You really should be aware of this or you might get the strangest results.&lt;/p&gt; &lt;hr&gt; &lt;/hr&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Jedi skills&lt;/h1&gt; &lt;p&gt;If you want to know more about finalizers, weak references, the GC and other goodies I highly recommend checking out &lt;a href="http://blogs.msdn.com/maoni/default.aspx"&gt;Maoni's WebLog&lt;/a&gt;. What better place to learn about this than from one of the developers?&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Over and out&lt;/p&gt; &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2286964" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Managed+Heap/default.aspx">Managed Heap</category><category domain="http://blogs.msdn.com/johan/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/johan/archive/tags/Finalizers/default.aspx">Finalizers</category><category domain="http://blogs.msdn.com/johan/archive/tags/Weak+References/default.aspx">Weak References</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Memory management in the .NET Framework</title><link>http://blogs.msdn.com/johan/archive/2007/04/20/memory-management-in-the-net-framework.aspx</link><pubDate>Fri, 20 Apr 2007 16:07:29 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2206941</guid><dc:creator>JohanS</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/johan/comments/2206941.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=2206941</wfw:commentRss><description>&lt;p&gt;This is a subject that has been covered before and I have no intention of writing the ultimate post on the subject. Still I think this is something that every good developer should know.&lt;/p&gt; &lt;h1&gt;Why do I need to know this?&lt;/h1&gt; &lt;p&gt;My colleagues and I are quite often asked about the necessity of knowing how the Garbage Collector (GC) works. After all, it isn't really necessary to know what's going on behind the scenes, right..? A developer shouldn't have to bother about how the framework works..? Or should he..?&lt;/p&gt; &lt;p&gt;Well you may be a pretty good bus driver even if you know nothing about engines. Basic stuff like not stepping on the break and the gas at the same time is probably enough. If you want to do F1 racing, on the other hand, you will want to know as much as you can about your car. So, if you're content doing small scale web applications or not so efficient winforms applications, then you probably don't have to bother. If you want to do front-line work, then you've got to get your hands dirty.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;The different generations&lt;/h1&gt; &lt;p&gt;In order to be effective the managed heap is trying to figure out which objects it can disregard and only check up on occasionally. Some objects may span the entire lifecycle of the application and others may be very short lived, so if an object stays alive for&amp;nbsp;a longer period of time the GC will check up on it less frequently. This is accomplished by dividing the&amp;nbsp;managed heap into three generations. Generations 0, 1 and 2.&amp;nbsp;An object will begin in generation 0 and if it is&amp;nbsp;in use for a long period of time it will travel through generations&amp;nbsp;0 to 2. A possible metaphor for this scenario would the following:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;You're asked to call a customer. You're pretty good with numbers&amp;nbsp;so you keep the phone number in your head.&amp;nbsp;(Generation 0)  &lt;li&gt;There is no reply and so you need to remember the phone number a little longer. Meanwhile you're given additional numbers to call.  &lt;li&gt;You know from past experience that your limit for keeping numbers in your head is 10, so once you reach that critical point you decide to write down the numbers you still&amp;nbsp;need on post-it notes (Generation 1)  &lt;li&gt;As the day goes on you keep transferring numbers from memory to post-its.  &lt;li&gt;Your desktop has now reached maximum capacity. It is cluttered with post-it notes, so you sort through them, determining which notes you still need. You throw away the ones&amp;nbsp;that are obsolete&amp;nbsp;and write down the remaining to your address book. (Generation 2)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Like I stated above; when an object is created it is put in Generation 0. The initial size limit of Generation 0 is determined by the size of the processor cache. This is dynamically changed depending on the allocation rate of the application. Once Generation 0 reaches its limit it will go through all the items in Generation 0, tag the obsolete objects for collection and remove them. This is called the Mark and Sweep phase. Everything that survives this sweep will be compacted and moved to Generation 1. The size limit of Generation 1 is also determined by the allocation rate of the application, and once it is reached a Generation 1 collection will occur. This will first mark and sweep all items in Generation 1, moving the surviving items to Generation 2, and then mark and sweep the items in Generation 0.&lt;/p&gt; &lt;p&gt;The healthy ratio between GC's in the different generations is approximately 100 - 10 - 1, so for 100 Generation 0 GC's you normally have 10 GC's of Generation 1 and 1 of Generation 2. A normal Generation 0 GC usually takes a few milliseconds. Performing a GC of Generation 1 rarely takes more than 30 milliseconds,&amp;nbsp;but a Generation 2 collection can take&amp;nbsp;quite some time depending on the application.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;The Large Object Heap&lt;/h1&gt; &lt;p&gt;To top it off we also have what is called "The Large Object Heap" (LOH). This is where anything larger than 85.000 bytes will be stored. The&amp;nbsp;LOH is collected each time a new segment needs to be reserved (see below), but it is &lt;em&gt;not&lt;/em&gt; compacted like generations 0, 1 and 2. When you perform a collection on the LOH you will also perform a GC on the other generations.&lt;/p&gt; &lt;p&gt;Now, if the limit is at 85.000 bytes, won't most of my objects end up on the LOH? - Well not necessarily. For example: A dataset may contain lots and lots of data, but the dataset object only contains references to other objects. The data in the columns are each stored in individual strings and as long as they're not larger than 85 KB you're clear.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;Memory segments&lt;/h1&gt; &lt;p&gt;The managed heap will reserve memory in segments. The size of the segments depend on the configuration. If &lt;span class="InlineCode"&gt;&amp;lt;gcServer enabled="true"/&amp;gt;&lt;/span&gt; you will reserve memory in 64 MB segments, otherwise you'll be doing it in 32 MB segments. LOH are reserved in 16 MB segments. Only Generation 2 and the LOH will span several segments.&lt;/p&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;What happens during GC?&lt;/h1&gt; &lt;p&gt;Let's say we're performing a full GC, including the LOH. This is what happens:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The objects on the LOH&amp;nbsp;are &lt;em&gt;Marked&lt;/em&gt;. Each item in the LOH is checked for references. If none are found it's ready to be collected.  &lt;li&gt;The LOH is &lt;em&gt;Swept&lt;/em&gt;. All marked objects are released from memory.  &lt;li&gt;The LOH is &lt;strong&gt;not&lt;/strong&gt; compacted.  &lt;li&gt;Generation 2 is &lt;em&gt;Marked.&lt;/em&gt;  &lt;li&gt;Generation 2 is &lt;em&gt;Swept.&lt;/em&gt;  &lt;li&gt;Generation 2 is compacted. (Imagine removing a few books from your bookcase, and then pushing the remaining books together freeing up continuous space at the end.)  &lt;li&gt;Generation 1 is &lt;em&gt;Marked.&lt;/em&gt;  &lt;li&gt;Generation 1 is &lt;em&gt;Swept.&lt;/em&gt; &lt;li&gt;Everything &amp;nbsp;that survived the sweep is compacted. &lt;li&gt;The pointer for where Generation 2 ends is updated. Everything that survived the sweep is now Generation 2. &lt;li&gt;Generation 0 is &lt;em&gt;Marked.&lt;/em&gt;  &lt;li&gt;Generation 0 is &lt;em&gt;Swept.&lt;/em&gt; &lt;li&gt;Everything that survived the sweep is compacted. &lt;li&gt;The pointer for where Generation 1 ends is updated. Everything that survived the sweep is now Generation 1.&lt;/li&gt;&lt;/ul&gt; &lt;h1&gt;&amp;nbsp;&lt;/h1&gt; &lt;h1&gt;A few quick tips&lt;/h1&gt; &lt;p&gt;This topic could off course be a &lt;em&gt;lot&lt;/em&gt; bigger, but here are some quick suggestions.&lt;/p&gt; &lt;h2&gt;Try to stay out of Generation 1&lt;/h2&gt; &lt;p&gt;Well off course Generation 1 is better than Generation 2, but you should aim for keeping only a select few objects in Generation 2. Those should be variables that are defined at the beginning of the application lifecycle and released at the end. In an ideal world all other variables&amp;nbsp;should be of the hit-and-run variety and never leave Generation 0.&lt;/p&gt; &lt;h2&gt;Don't call GC.Collect()&lt;/h2&gt; &lt;p&gt;This has been said before. It will be said again, and again, and again. You should &lt;em&gt;almost&lt;/em&gt; never call GC.Collect() manually. And by &lt;em&gt;almost&lt;/em&gt; I mean once in a lifetime, not once per application, and certainly not once per function call. I occasionally call GC.Collect() for testing purposes just to see if memory has been released. Normally you would never call it. The GC is self-balancing and by calling GC.Collect() you are disrupting that balance. Think of it as tampering with the eco-system, pouring sugar in the gasoline or whatever metaphor you prefer. :-)&lt;/p&gt; &lt;h2&gt;Avoid large objects&lt;/h2&gt; &lt;p&gt;If you can stay below the 85.000 byte limit, then do so. If not, consider reusing the&amp;nbsp;object.&amp;nbsp;When it comes to large objects it's better&amp;nbsp;to use one for a long time than to use many for short periods of time.&lt;/p&gt; &lt;h2&gt;Don't use finalizers&lt;/h2&gt; &lt;p&gt;When your object has a finalizer the finalize method will be called when the object is no longer alive. So far so good. Unfortunately&amp;nbsp;your object will be passed into the next generation,&amp;nbsp;since it's not yet ready to be collected. This means that all objects with a finalizer will &lt;em&gt;at least&lt;/em&gt; end up in Generation 1. Most likely in Generation 2.&lt;/p&gt; &lt;p&gt;Well, as I said: There is a lot more to cover on this. There are books to be written and songs to be sung, but you've got to draw the line somewhere. I will most certainly cover more of this in future posts.&lt;/p&gt; &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2206941" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/OutOfMemory/default.aspx">OutOfMemory</category><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Managed+Heap/default.aspx">Managed Heap</category><category domain="http://blogs.msdn.com/johan/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Why adding more memory won't resolve OutOfMemoryExceptions</title><link>http://blogs.msdn.com/johan/archive/2007/04/19/why-adding-more-memory-won-t-resolve-outofmemoryexceptions.aspx</link><pubDate>Thu, 19 Apr 2007 12:43:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2189486</guid><dc:creator>JohanS</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/johan/comments/2189486.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=2189486</wfw:commentRss><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;Quite often I am met with the incorrect assumption that out of memory exceptions can be resolved by adding more memory. I can understand why you'd think that, but actually it won't matter at all. Additional RAM may increase performance, but an additional 8GB of memory won't increase the available amount of memory for the .NET application.&lt;/p&gt; &lt;p&gt;Here's what you need to know:&lt;/p&gt; &lt;h2&gt;If you have a 32 bit machine then you have 2 GB of memory available.&lt;/h2&gt; &lt;p&gt;That's the way it is. Never mind if you have 512 MB or 8 GB of RAM. A 32-bit system can address 4 GB of virtual memory. 2 GB of those are reserved for the operating system, leaving 2 GB for each user mode process. If there is no RAM available we will use the page file and save infrequently used memory to disk instead. So additional RAM will cause fewer page faults, but the amount of memory available for the process is still only 2 GB.&lt;/p&gt; &lt;p&gt;(Actually you can tune this in boot.ini. There is a switch that will allow you to steal 1 GB from the OS and increase the limit for the user process from 2 GB to 3 GB. It still requires some additional tweaking though. I suggest looking at &lt;a href="http://support.microsoft.com/kb/820108/en-us"&gt;http://support.microsoft.com/kb/820108/en-us&lt;/a&gt;&amp;nbsp;for more information on this.)&lt;/p&gt; &lt;p&gt;Okay, so now that we know this it's time for the next vital piece of information:&lt;/p&gt; &lt;h2&gt;Your process will most likely be out of memory when it reaches ~800 MB&lt;/h2&gt; &lt;p&gt;- What!? How is that possible!? Didn't I just say that we have 2 GB available? I did, but there is another thing you really need to know about memory allocations:&lt;/p&gt; &lt;h2&gt;Memory allocations need to be continuous.&lt;/h2&gt; &lt;p&gt;If you want to allocate a 100 MB string, then you need 100 MB of &lt;em&gt;continuous&lt;/em&gt; space. Memory allocations don't work the way the file system does.&amp;nbsp;If we were talking about files we could save part of the file in one place, another part in another place, etc. but memory != file system. Open up the disk defragmenter and take a look at your hard drive. You may have 100 GB available on your 250 GB hard drive, but how much of that is continuous? The available memory for your process will eventually become just as fragmented as your hard drive. And as your memory becomes more and more fragmented it will be harder and harder to squeeze in those large allocations.&lt;/p&gt; &lt;p&gt;Let's say you and your party of four walk into a restaurant. The restaurant is packed with four seat tables so finding a seat shouldn't be a problem. Unfortunately there is 1-3 persons sitting at each table. So even if only half the seats are taken you are still unable to get your own table. The usher gets an OutOfSeatsException as he tries to seat you. :-)&lt;/p&gt; &lt;p&gt;The rule of thumb is that you'll begin seeing OutOfMemoryExceptions at around 800 MB. Off course this isn't set in stone. It&amp;nbsp;depends entirely on the average size of the objects you allocate and how fragmented your memory becomes. You might make it up to 1.2 GB or you might see the exceptions already at 550 MB.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h1&gt;So what can be done?&lt;/h1&gt; &lt;p&gt;Well if you're in the planning stage of a WebService that will load 4 GB images, process them somehow and then return them to the client you'll want to either:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Work with streams and make sure you never load the full image into memory&lt;/li&gt; &lt;li&gt;Set aside the money to invest in a 64 bit system&lt;/li&gt; &lt;li&gt;Rethink&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;I'm currently writing a bigger post on how the managed heap and garbage collector work, so expect more to come on the subject.&lt;/p&gt; &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2189486" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/OutOfMemory/default.aspx">OutOfMemory</category><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>I've upgraded and now my application doesn't work anymore</title><link>http://blogs.msdn.com/johan/archive/2007/01/23/i-ve-upgraded-and-now-my-application-doesn-t-work-anymore.aspx</link><pubDate>Tue, 23 Jan 2007 19:09:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1515283</guid><dc:creator>JohanS</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/johan/comments/1515283.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=1515283</wfw:commentRss><description>&lt;h1&gt;Scenario:&lt;/h1&gt; &lt;p&gt;A quite common scenario when working in the support industry is a call along theese lines:&lt;/p&gt; &lt;p&gt;"My application worked just fine, but now that I've upgraded to IE7, IIS6, Vista, etc. it doesn't work any more. This has got to be a bug! This new version of the software&amp;nbsp;obviously isn't any good, so when are you going to fix it?"&lt;/p&gt; &lt;p&gt; &lt;hr&gt;  &lt;p&gt;&lt;/p&gt; &lt;h1&gt;Is it a bug?&lt;/h1&gt; &lt;p&gt;Well, possibly. But most likely the bug doesn't lie within&amp;nbsp;IE, IIS&amp;nbsp;or the operating system. Instead you should look at your code to make sure you did everything following the recommended guidelines. Chances are that you didn't do things the right way originally, and for some reasons the previous version of the software was more forgiving.&lt;/p&gt; &lt;h1&gt;Example&lt;/h1&gt; &lt;p&gt;A little while ago I had the following scenario on my hands:&lt;/p&gt; &lt;p&gt;A customer had just upgraded their webservers from Windows 2000 to Windows 2003. After the upgrade&amp;nbsp;certain requests just "vanished" into thin air. The response never reached the clients. We managed to track down the problem to the following lines of code:&lt;/p&gt; &lt;div class="SampleCode"&gt;this.Page.Response.ClearContent();&lt;br&gt;this.Page.Response.Write(TextToWrite);&lt;br&gt;this.Page.Response.Flush(); &lt;br&gt;this.Page.Response.Close(); &lt;/div&gt; &lt;p&gt;Okay, so you probably see what is strange here. Why are they calling &lt;span class="InlineCode"&gt;Response.Flush()&lt;/span&gt; and &lt;span class="InlineCode"&gt;Response.Close()&lt;/span&gt;?&lt;/p&gt; &lt;p&gt;If we remove theese two lines and replace them with &lt;span class="InlineCode"&gt;Response.End()&lt;/span&gt; then everything works fine:&lt;/p&gt; &lt;div class="SampleCode"&gt;this.Page.Response.ClearContent();&lt;br&gt;this.Page.Response.Write(TextToWrite);&lt;br&gt;this.Page.Response.End();&lt;/div&gt; &lt;p&gt;Okay, so this is the proper way to do it. &lt;span class="InlineCode"&gt;Response.End()&lt;/span&gt; will call actually call &lt;span class="InlineCode"&gt;Response.Flush()&lt;/span&gt; and then gracefully end execution of the page, while &lt;span class="InlineCode"&gt;Response.Close()&lt;/span&gt; will simply "cut the cord". But how come it worked in IIS5 and not IIS6? Does this mean that IIS6 is a bad product? - Not at all!&lt;/p&gt; &lt;p&gt;One of the things that changed with IIS6 is that it now processes responses asynchronously. This means that in IIS5 all execution will be paused until the page has been sent, while in IIS6 the response will be put in a send-buffer, allowing IIS to immediately continue execution. This is one of the reasons why IIS6 is both faster and more secure than IIS5. The thread executing the page does not have to take the connection speed of the client into consideration. It can execute the page and move on to the next. In IIS5 all execution on the thread would be stopped until the client had downloaded every last bit. This made the server more vulnerable to Denial of Service (DOS) -attacks, and something as trivial as a bunch of clients with poor modem connections could impair the performance of the server.&lt;/p&gt; &lt;p&gt;In brief, here’s what happened with the old code: &lt;/p&gt; &lt;p&gt;IIS5:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Response.Flush sends data to client&lt;/li&gt; &lt;li&gt;Thread waits until data has been sent&lt;/li&gt; &lt;li&gt;Response.Close closes client connection &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;IIS6:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Response.Flush puts the data in a send buffer and immediately moves to the next line of code&lt;/li&gt; &lt;li&gt;Response.Close closes the client connection before the data has been sent &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Here’s what happens with the new code:  &lt;p&gt;IIS5:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Response.End is called&lt;/li&gt; &lt;ul&gt; &lt;li&gt;The data is sent to the client&lt;/li&gt; &lt;li&gt;IIS gracefully ends all further execution of the page &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;p&gt;IIS6:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Response.End is called&lt;/li&gt; &lt;ul&gt; &lt;li&gt;The data is transferred to the send buffer&lt;/li&gt; &lt;li&gt;IIS gracefully ends all further execution of the page &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;h1&gt;Summary:&lt;/h1&gt; &lt;p&gt;The old code was incorrect, but worked anyway due to the synchronous design of IIS5. As IIS6 switched to an asynchronous response model this stopped working. I can sympathize with anyone that feels that this is a bug/mistake, but in reality it isn't. In fact it is a very concious choice made to further improve performance and reliability. &lt;p&gt;/ Johan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1515283" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/Bugs/default.aspx">Bugs</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>SessionState Performance</title><link>http://blogs.msdn.com/johan/archive/2006/11/20/sessionstate-performance.aspx</link><pubDate>Mon, 20 Nov 2006 11:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1107563</guid><dc:creator>JohanS</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/johan/comments/1107563.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=1107563</wfw:commentRss><description>&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Problem:&lt;/H1&gt;
&lt;P&gt;Unable to make the session state request to the session state server.&lt;BR&gt;Please ensure that the ASP.NET State service is started and that the client and server ports are the same.&lt;BR&gt;If the server is on a remote machine, please ensure that it accepts remote requests by checking the value of &lt;SPAN class=InlineCode&gt;HKLM\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\AllowRemoteConnection&lt;/SPAN&gt;. &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Cause:&lt;/H1&gt;
&lt;P&gt;Excessive use of SessionState &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Resolution:&lt;/H1&gt;
&lt;P&gt;Minor tweaks can be made, but be aware. You are pushing SessionState to it's absolute limits. &lt;/P&gt;
&lt;HR&gt;

&lt;H1&gt;Scenario:&lt;/H1&gt;
&lt;P&gt;Judging from the number of calls we get it seems quite common for people to store all sorts of things in SessionState and to rely quite heavily on it. I would personally say that the rule of thumb is to avoid SessionState as much as possible. &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;The different ways of storing SessionState&lt;/H1&gt;
&lt;P&gt;You're probably already familiar with the three different ways of storing SessionState, but I'll recap them quickly, just to refresh your memory: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;H2&gt;InProc&lt;/H2&gt;In process. Works fine if you have only one web server. Great performance, but if the application pool recycles, then your SessionData is lost forever. 
&lt;LI&gt;
&lt;H2&gt;State Server&lt;/H2&gt;The simple out-of process solution. By using the ASP.NET State Server you can share data between web servers. The ASP.NET State Server can be run either on one of the web servers or on a separate server. 
&lt;LI&gt;
&lt;H2&gt;SQL Server&lt;/H2&gt;Using SQL server isn't that different from using the State Server. SQL Server may be a tiny bit slower performance-wise, but the main benefit is that you can set up a fail-over cluster.&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Common myths&lt;/H1&gt;
&lt;P&gt;There are some common misunderstandings regarding SessionState and it's uses. The ones I come across most frequently would probably be the following: &lt;/P&gt;
&lt;H2&gt;Myth:&lt;/H2&gt;"SessionState is really efficient. If you store all datasets, etc. in a SessionVariable it's like having the data in RAM, rather than on disk" 
&lt;H2&gt;Fact:&lt;/H2&gt;When storing session data out of process it is serialized, stored and deserialized. This is a CPU-&amp;nbsp;and memory consuming process and if you store large objects in SessionState you will use a lot of resources to handle the data. For small chunks of data I'd recommend cookies, hidden controls (ViewState)&amp;nbsp;or even query strings. For larger objects... Well, do you really need them for every single request? 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;&amp;nbsp;&lt;/H2&gt;
&lt;H2&gt;Myth:&lt;/H2&gt;"The Server will only retrieve SessionState when I actually read or write to it." 
&lt;H2&gt;Fact:&lt;/H2&gt;Sorry, but that's incorrect as well. The data will be deserialized and serialized with each request unless you have clearly specified otherwise. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;&amp;nbsp;&lt;/H2&gt;
&lt;H2&gt;Myth:&lt;/H2&gt;"It doesn't matter what type of data I store in SessionState." 
&lt;H2&gt;Fact:&lt;/H2&gt;It does matter, and it matters a lot. For example; a 40KB string and a 40KB multi-dimensional array are not equivalent. The data must be serialized and deserialized, and serializing a string is a lot less CPU-consuming than serializing a complex array. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;&amp;nbsp;&lt;/H1&gt;
&lt;H1&gt;What is serialization anyway?&lt;/H1&gt;
&lt;P&gt;Serialization means transforming an object to a stream of bytes. This stream of bytes can then be sent over the web, saved to disk, etc. and be recreated on demand. When serializing the worker process takes your complex object and transform it to a simple byte stream that is easily dealt with.&amp;nbsp;This byte stream in itself is pretty useless until you deserialize it. You can not access its properties until you've "unpacked it". Think of it as a .cab archive or instant coffee. :) &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Increasing performance&lt;/H1&gt;
&lt;P&gt;If you are aware from the start that SessionState isn't the most effective way to store data, then you should be fine. If you're stuck with the ungrateful task of cleaning up someone else's mess, then you have a little more work to do.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;The planning phase&lt;/H2&gt;
&lt;P&gt;Like I said, you should always try to limit your use of SessionState. It's quite common to store data "for later use", but unless you absolutely need it right now, then why store it in Session State? And if you absolutely need it right now, then why not use ViewState, cookies&amp;nbsp;or some other means of temporary storage like a database? Here are some samples: &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;If you have a huge dataset that was really taxing to get, then save it to a temporary table or take it as a hint to rethink your database design. 
&lt;LI&gt;Form data should be kept in ViewState or possibly in cookies. 
&lt;LI&gt;Try really, really hard to keep Objects out of SessionState. Especially STA COM objects. If you really have to save an STA COM object, then remember to set the &lt;SPAN class=InlineCode&gt;AspCompat&lt;/SPAN&gt; attribute of the &lt;SPAN class=InlineCode&gt;@ Page&lt;/SPAN&gt; directive. 
&lt;LI&gt;Disable Session State on all pages that don't require it, and set it to read-only on pages that don't require write-access. This is done with &lt;SPAN class=InlineCode&gt;&amp;lt;@ Page EnableSessionState="..."&amp;gt;&lt;/SPAN&gt; (Framework 2.0) 
&lt;LI&gt;Read the article &lt;A href="http://msdn2.microsoft.com/en-us/library/ms998530.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms998530.aspx"&gt;Improving .NET Application Performance and Scalability&lt;/A&gt;. Especially &lt;A href="http://msdn2.microsoft.com/en-us/library/ms998549.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms998549.aspx"&gt;Chapter 6&lt;/A&gt;&amp;nbsp;which deals with ASP.NET.&lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;Existing applications&lt;/H2&gt;
&lt;P&gt;There are a few things worth tryng if you're running an application and suddenly find yourself with a StateServer on it's knees begging for mercy. Please note that most of this is to be considered respiratory only. A few more users and you'll probably be facing the same scenario again. So my personal suggestion would probably be to quickly get the server up and running within acceptable parameters and then immediately begin working on a redesign. Anyway. here are my quick tips for a quick fix:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Disable Session State on all pages that don't use it, or set it to read-only by using the &lt;SPAN class=InlineCode&gt;EnableSessionState&lt;/SPAN&gt; attribute in the &lt;SPAN class=InlineCode&gt;@ Page&lt;/SPAN&gt; directive (Framework 2.0) 
&lt;LI&gt;If you've hit the ceiling and are running the in-process state server, then there might be some extra performance to be gained by setting up an out-of process State Server on a separate machine. 
&lt;LI&gt;If you're using the out of process StateServer, then you might want to increase the timeout according to the following article:&lt;BR&gt;&lt;A href="http://support.microsoft.com/?kbid=308097" target=_blank mce_href="http://support.microsoft.com/?kbid=308097"&gt;State server logs Event ID 1072 or Event ID 1076&lt;/A&gt; 
&lt;LI&gt;You might also want to increase the available number of ports on the StateServer by following the guidelines in this article: (I know it doesn't mention StateServer, but the solution is the same.)&lt;BR&gt;&lt;A href="http://support.microsoft.com/?kbid=319502" target=_blank mce_href="http://support.microsoft.com/?kbid=319502"&gt;PRB: "WSAEADDRESSINUSE" Error Message When You Try to Connect Through an Anonymous Port After You Increase the IMAP Connection Limit&lt;/A&gt; 
&lt;LI&gt;There is also a possibility that this fix will help you out:&lt;BR&gt;&lt;A href="http://support.microsoft.com/?kbid=896600" target=_blank mce_href="http://support.microsoft.com/?kbid=896600"&gt;FIX: You may receive an error message when you use the ASP.NET State Server service to store ASP.NET session state in the .NET Framework 1.1&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;H1&gt;More than one StateServer:&lt;/H1&gt;
&lt;P&gt;If all else fails you can actually have more than one StateServer, provided that you have a webfarm. If you set up your load balancer to use sticky sessions you could actually run each web server with its own StateServer. This would mean that each web server would have its own settings for SessionState. This gives you many options for load balancing. If you, for example, have 8 web servers you could divide the servers into pairs and let each pair share an out of process&amp;nbsp;StateServer. This would give you a solution with 8 web server and 4 state servers. You could even have a separate fail-over cluster for each web server. But as much as this would please your hardware vendor you're probably&amp;nbsp;compensating&amp;nbsp;for poor planning by adding horsepower.&lt;/P&gt;
&lt;P&gt;Well I guess that's all for now.&lt;/P&gt;
&lt;P&gt;/ Johan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1107563" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/johan/archive/tags/SessionState/default.aspx">SessionState</category><category domain="http://blogs.msdn.com/johan/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Are you getting OutOfMemoryExceptions when uploading large files?</title><link>http://blogs.msdn.com/johan/archive/2006/11/15/are-you-getting-outofmemoryexceptions-when-uploading-large-files.aspx</link><pubDate>Wed, 15 Nov 2006 12:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1080526</guid><dc:creator>JohanS</dc:creator><slash:comments>30</slash:comments><comments>http://blogs.msdn.com/johan/comments/1080526.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johan/commentrss.aspx?PostID=1080526</wfw:commentRss><description>&lt;H1&gt;Problem:&lt;/H1&gt;
&lt;P&gt;Using the WebClient.Upload method for posting large files will eventually leave you stranded with OutOfMemoryExceptions.&lt;/P&gt;
&lt;H1&gt;Cause:&lt;/H1&gt;
&lt;P&gt;WebClient.Upload reads the entire file to memory by default.&lt;/P&gt;
&lt;H1&gt;Resolution:&lt;/H1&gt;
&lt;P&gt;Build your own uploader.&lt;/P&gt;
&lt;HR&gt;

&lt;H1&gt;Scenario:&lt;/H1&gt;
&lt;P mce_keep="true"&gt;One of my customers was using &lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;WebClient.Upload&lt;/SPAN&gt; in a Winforms application to transfer files to a webserver. The idea in itself was fine, but when they transferred a couple of large files they'd get OutOfMemoryExceptions.&amp;nbsp;When uploading a 500 MB file the application would need&amp;nbsp;approximately 520 MB of memory and if you uploaded&amp;nbsp;a few&amp;nbsp;large files&amp;nbsp;after each other you quickly hit the roof. Running &lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;GC.Collect();&lt;/SPAN&gt; after each transfer didn't help.&amp;nbsp;Judging from the number of hits on the internet for this scenario they weren't the only ones with this problem.&lt;/P&gt;
&lt;P mce_keep="true"&gt;This is the code they were using:&lt;/P&gt;
&lt;DIV class=SampleCode&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: teal; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;WebClient&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt; oWeb = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;WebClient&lt;/SPAN&gt;();&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;oWeb.UploadFile(&lt;SPAN style="COLOR: maroon"&gt;"http://localhost/test.aspx"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: maroon"&gt;"c:\\bigfile.cab"&lt;/SPAN&gt;);&lt;/SPAN&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P mce_keep="true"&gt;Okay, so why was this&amp;nbsp;happening?&lt;BR&gt;Well, first of all I wouldn't recommend running &lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;GC.Collect();&lt;/SPAN&gt; in any application. A lot has been written on this allready, but if you're interested in why I suggest you look at &lt;A class="" href="http://blogs.msdn.com/ricom/archive/2003/12/02/40780.aspx" target=_blank mce_href="http://blogs.msdn.com/ricom/archive/2003/12/02/40780.aspx"&gt;Rico Mariani's post on the subject&lt;/A&gt;. Anyway, for testing purposes we ran the following instead:&lt;/P&gt;
&lt;DIV class=SampleCode&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: teal; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;GC&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;.Collect(3);&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: teal; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;GC&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;.WaitForPendingFinalizers();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: teal; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;GC&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;.Collect(3);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P mce_keep="true"&gt;And&amp;nbsp;this cleared the memory.&amp;nbsp;So why isn't this a valid solution? Well, like I said, I wouldn't recommend&amp;nbsp;using&amp;nbsp;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;GC.Collect();&lt;/SPAN&gt; in any application, and why read the entire file to memory when you can&amp;nbsp;stream it? I looked up the UploadFile-method and it seems like it does read the entire file to a byte array before posting. This is great for smaller files, but in this particular scenario it wasn't too good. So what I did was to write my own uploader:&lt;/P&gt;
&lt;DIV class=SampleCode&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;o:p&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; MyUploader(&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; strFileToUpload, &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; strUrl)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt; 
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; strFileFormName = &lt;SPAN style="COLOR: maroon"&gt;"file"&lt;/SPAN&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;Uri&lt;/SPAN&gt; oUri = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Uri&lt;/SPAN&gt;(strUrl);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; strBoundary = &lt;SPAN style="COLOR: maroon"&gt;"----------"&lt;/SPAN&gt; + &lt;SPAN style="COLOR: teal"&gt;DateTime&lt;/SPAN&gt;.Now.Ticks.ToString(&lt;SPAN style="COLOR: maroon"&gt;"x"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// The trailing boundary string&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;byte&lt;/SPAN&gt;[] boundaryBytes = &lt;SPAN style="COLOR: teal"&gt;Encoding&lt;/SPAN&gt;.ASCII.GetBytes(&lt;SPAN style="COLOR: maroon"&gt;"\r\n--"&lt;/SPAN&gt; + strBoundary + &lt;SPAN style="COLOR: maroon"&gt;"\r\n"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// The post message header&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;StringBuilder&lt;/SPAN&gt; sb = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;StringBuilder&lt;/SPAN&gt;();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"--"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(strBoundary);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"\r\n"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"Content-Disposition: form-data; name=\""&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(strFileFormName);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"\"; filename=\""&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: teal"&gt;Path&lt;/SPAN&gt;.GetFileName(strFileToUpload));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"\""&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"\r\n"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"Content-Type: "&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"application/octet-stream"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"\r\n"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;sb.Append(&lt;SPAN style="COLOR: maroon"&gt;"\r\n"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; strPostHeader = sb.ToString();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;byte&lt;/SPAN&gt;[] postHeaderBytes = &lt;SPAN style="COLOR: teal"&gt;Encoding&lt;/SPAN&gt;.UTF8.GetBytes(strPostHeader);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// The WebRequest&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;HttpWebRequest&lt;/SPAN&gt; oWebrequest = (&lt;SPAN style="COLOR: teal"&gt;HttpWebRequest&lt;/SPAN&gt;)&lt;SPAN style="COLOR: teal"&gt;WebRequest&lt;/SPAN&gt;.Create(oUri);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;oWebrequest.ContentType = &lt;SPAN style="COLOR: maroon"&gt;"multipart/form-data; boundary="&lt;/SPAN&gt; + strBoundary;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;oWebrequest.Method = &lt;SPAN style="COLOR: maroon"&gt;"POST"&lt;/SPAN&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// This is important, otherwise the whole file will be read to memory anyway...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;oWebrequest.AllowWriteStreamBuffering = &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Get a FileStream and set the final properties of the WebRequest&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;FileStream&lt;/SPAN&gt; oFileStream = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;FileStream&lt;/SPAN&gt;(strFileToUpload, &lt;SPAN style="COLOR: teal"&gt;FileMode&lt;/SPAN&gt;.Open, &lt;SPAN style="COLOR: teal"&gt;FileAccess&lt;/SPAN&gt;.Read);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;long&lt;/SPAN&gt; length = postHeaderBytes.Length + oFileStream.Length + boundaryBytes.Length;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;oWebrequest.ContentLength = length;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;Stream&lt;/SPAN&gt; oRequestStream = oWebrequest.GetRequestStream();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Write the post header&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;oRequestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Stream the file contents in small pieces (4096 bytes, max).&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;byte&lt;/SPAN&gt;[] buffer = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Byte&lt;/SPAN&gt;[&lt;SPAN style="COLOR: blue"&gt;checked&lt;/SPAN&gt;((&lt;SPAN style="COLOR: blue"&gt;uint&lt;/SPAN&gt;)&lt;SPAN style="COLOR: teal"&gt;Math&lt;/SPAN&gt;.Min(4096, (&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;)oFileStream.Length))];&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; bytesRead = 0;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;while&lt;/SPAN&gt; ((bytesRead = oFileStream.Read(buffer, 0, buffer.Length)) != 0)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;oRequestStream.Write(buffer, 0, bytesRead);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;oFileStream.Close();&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Add the trailing boundary&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;oRequestStream.Write(boundaryBytes, 0, boundaryBytes.Length);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;WebResponse&lt;/SPAN&gt; oWResponse = oWebrequest.GetResponse();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;Stream&lt;/SPAN&gt; s = oWResponse.GetResponseStream();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;StreamReader&lt;/SPAN&gt; sr = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;StreamReader&lt;/SPAN&gt;(s);&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: teal"&gt;String&lt;/SPAN&gt;&amp;nbsp;sReturnString = sr.ReadToEnd();&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp;Clean up&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="COLOR: green"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; oFileStream.Close();&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; oRequestStream.Close();&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; s.Close();&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sr.Close();&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt; sReturnString;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;One of the things worth noting is that you need to set&amp;nbsp;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;oWebrequest.AllowWriteStreamBuffering = &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;; &lt;/SPAN&gt;&lt;/o:p&gt;Otherwise you will read the entire file to memory anyway. This is because the default behavior of the WebRequest is to buffer the entire request in case it needs to re-send it due to authentication, connectivity problems, etc. Again, this is a default behavior that normally is a performance boost, but in this case is a performance killer. &lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;So what was the end result?&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none" mce_keep="true"&gt;During my first test runs the application needed as much memory as the file I was trying to upload, and then some. So in order to upload a 500 MB .cab-file the application needed at least 520 MB. The application using the custom uploader never went above 23 MB.&lt;/P&gt;
&lt;P mce_keep="true"&gt;End of transmission&lt;/P&gt;
&lt;P mce_keep="true"&gt;/ Johan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1080526" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johan/archive/tags/Upload/default.aspx">Upload</category><category domain="http://blogs.msdn.com/johan/archive/tags/Stream/default.aspx">Stream</category><category domain="http://blogs.msdn.com/johan/archive/tags/OutOfMemory/default.aspx">OutOfMemory</category><category domain="http://blogs.msdn.com/johan/archive/tags/WebClient/default.aspx">WebClient</category><category domain="http://blogs.msdn.com/johan/archive/tags/Performance/default.aspx">Performance</category></item></channel></rss>