If broken it is, fix it you should

Using the powers of the debugger to solve the problems of the world - and a bag of chips    by Tess Ferrandez, ASP.NET Escalation Engineer (Microsoft)

ASP.NET Memory: If your application is in production… then why is debug=true

ASP.NET Memory: If your application is in production… then why is debug=true

Rate This
  • Comments 86

Statement

 

“Ensure that the debug="false" on the <compilation> element in the web.config file of each and every ASP.NET application on the server. The default during development is "true" and it is a common mistake to allow this development time setting to find its way onto production servers during deployment. You don't need it set to true in production and it often leads to memory overhead and inefficiencies.”

 

What problems does leaving debug=true cause?

 

There are three main differences between debug=true and debug=false:

 

  1. ASP.NET Timeouts
  2. Batch compilation
  3. Code optimization

 

ASP.NET Timeouts

 

When debug is set to true, asp.net requests will not time out. This is to allow you to debug with visual studio at your own pace without having to worry about the requests suddenly disappearing. Of course in a production environment timeouts are crucial to avoid for requests to be stuck indefinitely, so this is reason #1 to make sure debug is set to false when the application is deployed into production.

 

Batch compilation

 

In short, when debug=true, we don’t batch compile, when debug=false we do…

 

What does this mean? 

 

When an aspx, asax, or ascx page is first requested it gets compiled into an assembly. This assembly has a name like 3ks0rnwz.dll or similar (8 characters) and stores the class for the actual ascx, asax, or aspx page (not the code behind).  The assembly goes into a folder in the C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files with the same name as the application.

 

The code behind class gets compiled into the main dll for the assembly, and it along with all the other dlls in the applications bin directory get shadow copied to the Temporary ASP.NET files.

 

Back to the 3ks0rnwz.dll… If we have debug=true, we create one dll per aspx, asax, or ascx page and this dll is compiled in debug mode, so if you have 100 web pages, you will have 100 assemblies, and they are generated as the pages are requested.

 

If we instead have debug=false, we batch compile, which means that the first time you request any page in your application, we compile the whole batch into one big assembly. This is a truth with some modification.  The user controls (ascx pages) are compiled into a separate assembly from the aspx pages and the aspx pages are compiled in groups based on what other files (read usercontrols) they include. The global.asax is also compiled separately.  And batch compilation occurs on a directory bases, meaning that if your application has subdirectories, the subdirectories are compiled separately to avoid for example name clashes, as it is valid to have two aspx pages with the same name in different directories. But all in all, instead of 100 dlls, you might end up with 3 or 4.

 

Ok, big deal? It’s the same code so the size of the combined assemblies shouldn’t much differ from the size of the individual assemblies right?  Truth is, there probably isn’t an enormous difference. But… and this is a big but… there is overhead for each dll, and if the dll is compiled in debug mode there is overhead for items needed for debugging, and … last but not least (in fact probably most important), the assemblies won’t be laid exactly side by side, so with a large number of assemblies you start fragmenting the virtual address space making it harder and harder to find large enough spaces to store the managed heaps, potentially causing out of memory exceptions. 

 

One caution even if you have debug=false, is that if you go in and change something in one of your aspx pages, this page will have to be recompiled, but this doesn’t cause an appdomain reload so the whole application is not batch compiled again.  This has the effect that the page will now get recompiled separately and get its own dll, so don’t change your aspx pages on a live server too often. 

 

There is a setting in machine.config determining how many recompiles are allowed before the app domain restarts, by default it is set to 15, so after 15 recompilations the app domain will restart, just as it would if you touched the web.config or touched the bin directory.  

 

Code optimization

 

In order to be able to step through code line by line the JITter can’t really optimize the code which means that your debug dlls will be less performant than if they were compiled in release mode.

 

So as you can probably figure, there is a large benefit to having debug=false in production…

 

How can you identify it in a memory dump?

 

To find out if any of the applications on your server run with debug=true you can run a nifty command in sos.dll called !finddebugtrue which will list out all applications where debug=true in the web.config, now how easy is thatJ

 

0:016> !finddebugtrue

Debug set to true for Runtime: 61b48dc, AppDomain: /MyDebugApplication

Debug set to true for Runtime: 1f50e6d8, AppDomain: /MemoryIssues

Total 16 HttpRuntime objects

 

And to find out if you forgot to compile some of your assemblies in release mode run !finddebugmodules

 

0:016> !finddebugmodules

Loading all modules.

Searching for modules built in debug mode...

 

MyDebugApplication.dll built debug

MemoryIssues.dll built debug

fl4sq-9i.dll built debug

wepr1t3k.dll built debug

r9ocxl4m.dll built debug

zmaozzfb.dll built debug

 

Done Seaching

 

 

The dlls above with weird 8 character names are the dlls generate when JITing the aspx pages, so they will go away when debug=false.

 

 

Oh, before I forget… when you change from debug=true to debug=false it is a good idea to clean out your Temporary ASP.NET files for this application so you don’t have some old junk in there causing it to still not batch compile.

 

 

In ASP.NET 2.0 there is a switch that can be turned on in machine.config that turns off all debug=true, so in 2.0 applications you can do this directly without worrying about finding out which applications do and don’t have it.

 

<configuration>

    <system.web>

          <deployment retail=”true”/>

    </system.web>

</configuration>

 

If you want some more goodies about debug=true, read ScottGu’s blog post about it http://weblogs.asp.net/scottgu/archive/2006/04/11/442448.aspx

 

 

 

 





  • Recently my colleague Doug wrote a nice post on Nine tips for a healthy &quot;in production&quot; ASP.NET application....
  • if yo ugo back and change debug=true to debug=false wont you get a compilation error? do yo need to restart iis after doing this?
  • Another slight app startup performance hit you'll have if you set debug to false is that (and i'm guessing here) when the ASP.Net app creates a dll for each aspx page, its not finding a unique base address in memory for each dll.  So when the AppDomain loads it will have to spend time rebasing each and every dll into an empty spot in memory.  if you only have 3-4 dlls, its much less of a hit.
  • Gregor,

    You should not get an error message just by changing from debug=true to debug=false, but to avoid having some dlls batch compiled and some not i would recommend deleting the temporary asp.net files when you next IISreset
  • Ok &amp;ndash; I admit, I have done this, you take the web.config from development, it gets rolled up to...
  • Uno degli errori pi&#249; comuni quando si effettua il deployment in ambiente di produzione di una applicazione...
  • We did get an error for a UserControl that it reported it could not load the FileName_ascx class due to multiple versions in the Temp ASP.NET folder.

    We identified that we had two user controls with the same file name in diferent Folders of the same Web App. The also had diferent namespaces and never through this exception until we set debug="false". We even wiped the Temp ASP.NET directory clean on an IISreset.

    The only way we could fix the error, was by renaming the ascx file of one of the two.

    Is this correct...? Was there a better way to fix this?

    BTW...
    [KissUpText]
    Tess, your posts have been very helpfull to our development team, and we really appreciate all the information you have given away.
    [/KissUpText]
  • Hi Robbie,

    Thanks for the nice comment:)

    I am assuming that you are getting "CS1595: 'UserControls.WebUserControl2' is defined in multiple places; using definition from 'c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files\usercontrols\293a1a4b\dbb2d387\cisxatg3.dll'
    "  or similar.

    The problem basically occurrs if you are using src rather than CodeBehind and your cs or vb files contain a definition for exactly the same class in exactly the same namespace.  The error is really the same as what you would get if you tried to compile a dll with another class defined twice in the same namespace.

    The reason i am saying it happens when you use src is because if you would use CodeBehind you would have gotten an error at compile time.

    If the usercontrols are really the same I would avoid creating a copy, and instead using the one from the other folder. If they are different I would either give the different names if possible, and if not, make sure that the source classes are in different namespaces, such as ProjectName.FolderName.MyUserControl

    The reason you are seeing it now and not before is because you are now batch-compiling everything into one dll.

    Hope this helps.
  • Thanks Tess,

    Sorry, I should have include the exception message:
    CS1595: '_ASP.BrokerInformation_ascx' is defined in multiple places; using definition from 'c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files\root\f4fb459b\4deb68eb\1huxv2vg.dll'

    And actually, we are using the CodeBehind attribute:

    -------------------------------------------------------------------------
    UserControl #1:
    <%@ Control Language="c#" AutoEventWireup="false" Codebehind="BrokerInformation.ascx.cs" Inherits="WAB.Websites.GA.UserAdmin.UserControls.BrokerInformation" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>">http://schemas.microsoft.com/intellisense/ie5"%>

    CodeBehind #1:
    namespace WAB.Websites.GA.Admin.UserControls
    {
    /// <summary>
    /// Summary description for BrokerInformation.
    /// </summary>
    public class BrokerInformation : UserControlBase
    ...

    -------------------------------------------------------------------------

    UserControl #2:
    <%@ Control Language="c#" AutoEventWireup="false" Codebehind="BrokerInformation.ascx.cs" Inherits="WAB.Websites.GA.Admin.UserControls.BrokerInformation" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>

    CodeBehind #2:
    namespace WAB.Websites.GA.UserAdmin.UserControls
    {
    /// <summary>
    /// Summary description for BrokerInformation.
    /// </summary>
    public class BrokerInformation : UserControlBase
    ...

    (this is how it looked when the error was happening)

    Also, yes they are different controls, and we have since renamed the #2 control AdminBrokerInformation.ascx.

    So we are no longer receiving the error, but it looks to me that within a ASP.NET (1.x) application, all aspx and ascx files must be named unique (and not in the FQCN meaning of unique), because they all end up under the same "_ASP.*" namespace.

    please let me know if:
    Assert.IsTrue(MyCommentAbove.IsCorrect);
Page 1 of 6 (86 items) 12345»
Leave a Comment
  • Please add 2 and 4 and type the answer here:
  • Post