Proactive Debugging

Proactive debugging is a strategy whereupon bugs are found as early as possible during development. These are problems that survived preemptive debugging. The later a bug is found, the more expensive to resolve the problem. Proactive debugging is another method to find bugs earlier. Visual Studio is a useful tool for proactive debugging. Managed Debugging Assistants (MDAs) and Code Analysis are two features of Visual Studio that are helpful in this regard.

Managed Debugging Assistants

At run time, MDAs isolate problems related to interoperability, such as PInvoke and COM wrappers. When a problem is detected, the MDA displays an informational dialog box and interrupts the application. For example, there is an MDA (DllMainReturnsFalse) that detects when DllMain returns false. DllMain is the entry point function for a dynamic-link library (DLL). If DllMain returns false, that is an indication of an error condition. Here is another example. The DangerousThreadingAPI MDA detects when the System.Threading.Thread. Suspend method is called on another thread, which may cause an ungraceful interruption of that thread. Because MDAs act at run time, the proper MDAs must be selected before the assembly is executed. MDAs are critical because they identify potential and complex problems that are otherwise difficult to find while debugging managed code.

The MDA does interrupt the debugger but is primarily informational and otherwise will not alter the execution of the application. MDAs are available in Visual Studio but not other debuggers, such as Windbg or DbgCLR. For Web applications, there are three ways to configure MDAs: Microsoft Visual Studio, environment variable, or the registry.

Visual Studio

From the Visual Studio menu, you can choose the appropriate MDA. Select the Debug menu and choose Exceptions. The Exceptions dialog box will appear. One of the groups is Managed Debugging Assistants. See 9-3. Enable or disable a MDA category by selecting or clearing the Thrown check box to the right of Managed Debugging Assistants. Alternatively, expand the Managed Debugging Assistants category to view a specific MDA. You can then set the status of an individual MDA with the Thrown check boxes. With MDAs, the User-unhandled option is always set and not relevant.

MDAs in the Exceptions dialog box.

Figure 9-3. MDAs in the Exceptions dialog box.

Environment variable

Control the status of an individual MDA or category with the COMPLUS_MDA environment variable. Here is an example:

COMPLUS_MDA =0;DangerousThreadingAPI

COMPLUS_MDA is a semicolon-delimited string and can contain multiple elements. The string is also case sensitive. Each element identifies a specific MDA or special item. See 9-2 for a list of special items. Based on the following table, the preceding code example enables the DangerousThreadingAPI MDA, while disabling all other MDAs.

Table 9-2. Special Items For The Complus_Mda Environment Element

Special Item

Description

0

Disable MDAs

1

Read MDAs from configuration file

managedDebugger

Enable MDAs that are implicitly enabled when managed application is started in debugger

unmanagedDebugger

Disable MDAs that are implicitly enabled when managed application is started in debugger

Registry

You can also use the registry to enable and disable MDAs as a group. This method will affect all .NET applications on the system. Of course, be careful when mucking around in the registry. Improper changes to the registry can adversely affect the behavior of the .NET Framework or operating system. Set the HKEY_LOCAL_MACHINESOFTWAREMicrosoft.NETFramework key to control the status of MDAs. Add a string value named MDA to the key. Set the value to 1 to enable every MDA. Set the value to 0 to disable all MDAs.

MDA Example

The following code will cause an MDA to be invoked. In this code, one thread suspends another thread. This is done using the System.Threading.Thread.Suspend method. This behavior is potentially dangerous and will trigger the DangerousThreadAPI MDA at run time when Thread.Suspend is called. The program will then be interrupted, and a dialog box is displayed for the MDA. See 9-4.

public partial class _Default : System.Web.UI.Page {
    protected  void Page_Load(object sender, EventArgs  e) {
        Thread t  = new Thread(new ThreadStart(MyThread));
        t.Start () ;
        t.Suspend() ;
    }
    public void MyThread(){
        while (true) {
            Thread.Sleep(1000);
        }
    }
}
The dialog box and message for the DangerousThreadingAPI MDA.

Figure 9-4. The dialog box and message for the DangerousThreadingAPI MDA.

Code Analysis

Code Analysis is a set of rules for writing quality applications in .NET. Each rule represents a best practice or policy for managed coding as defined in the Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, by Krzysztof Cwalina and Brad Abrams (Addison-Wesley, 2005), which is part of the Microsoft .NET Development Series. Examples of rules are Do not initialize unnecessarily, Remove calls to GC.KeepAlive, and Do not catch general exception types. Code analysis rules are grouped into categories, such as Design, Globalization, Interoperability, and Maintainability rules. Code analysis inspects your code during the build process. Any problems are displayed as warnings in the Error List window. Code Analysis is only available in Visual Studio Team System 2008 Developer Edition and Visual Studio Team System 2008 Team Suite. The origin of Code Analysis is FXCop. FXCop is a stand-alone tool that examines assemblies for coding problems. Code Analysis is beyond the scope of this chapter; however, Chapter 10, presents a complete discussion on the topic.

Performance Monitoring

Use the Reliability and Performance Monitor tool to track system metrics and internal information on an application, group of applications, or operating system. The tool is located in the Control Panel as part of the Administrators Tool group. As the name implies, Reliability and Performance Monitor is separated into two components. The Reliability Monitor reports on the health of the system and hardware. It also tracks key events, such as software installs and uninstalls. Administrators could use the Reliability Monitor to monitor scalability and plan future deployments. With the Performance Monitor, you can select and monitor performance counters on applications or the operating system. A developer could use the performance monitor to track a variety of problems, including memory leaks and runaway handles. The Reliability and Performance Monitor can present data in a variety of views, such as a chart, dashboard, and report. This allows the display of even complicated data in an easy-to-understand format. The Reliability and Performance Monitor collects data over a period of time. Sometimes this can amount to a mountain of information. In this circumstance, you can save the data to a log file, print the resulting report, get a cup coffee, find a deserted closet, and enjoy interesting reading.

With the Performance Monitor, you can select and monitor one or more counters. A counter represents a data point, such as the number of CLR exceptions that have been thrown, the number of bytes on all managed heaps, or the number of finalization survivors. You can select the desired counters and then the appropriate visual representation. There are several counters for native and managed applications. There are even counters for ASP.NET. Counters for managed applications are easily identified—they have the .NET prefix.

It is common to set several counters in the Performance Monitor. A Data Collector set is a reusable collection of counters. This is a convenient way to save an assortment of counters and reuse as needed. When a Data Collector is started, the Performance Monitor collects data on the counters found in the set. You end the collection process by stopping the Data Collector set. The Reliability and Performance Monitor comes with standard Data Collector sets: LAN Diagnostics, System Diagnostics, System Performance, and Wireless Diagnostics. You can also create user-defined Data Collector sets.

The Performance Monitor application programming interface (API) is available to managed code. You can use performance counters in your program. The PerformanceCounter class in the System.Diagnostics namespace is a wrapper for the Performance Monitor API. An instance of the PerformanceCounter class represents a single counter. With the resulting object, you can read the value of the associated performance counter.

Performance Monitor example

As mentioned, performance monitoring is an excellent tool for detecting potential memory leaks in managed applications. One of the first questions should be, "Is the memory leak in native or managed memory?" Performance Monitor can plot a line graph of this comparison. When referring to native memory, this refers to the overall memory of the application, including managed memory. Therefore a growth in managed memory has an equal impact on native memory. Where n is native memory, m is managed memory, and im is the increase in managed memory, this formula represents the relationship n + im = m + im. If the relation between managed and native memory becomes n + im + x = m + im, where x is a disproportionate increase of native memory, a leak in native memory is implied. This is particularly true if the increase is continuous and does not plateau. Conversely, if disproportionate growth is shown in managed memory, a leak in managed memory is the likely problem.

For a Web application, you can set counters on the worker process to track memory requirements. For IIS 7.0, the worker process is w3wp.exe. In our example, two Performance Monitor counters are selected for the worker process. First, in the .NET CLR Memory group, # Bytes In All Heaps counter is selected. The instance is the w3wp.exe worker process. The # Bytes In All Heaps counter returns the total amount of managed memory used, which is the sum of Generations 0, 1, 2, and the Large Object heap. Second, in the Process group, select the Private Bytes counter. Specific steps for selecting these two counters are presented below. The instance is again w3wp.exe. Private Bytes is the total of native memory being used. 9-5 is a line graph of these two performance counters. The top line is native memory; the bottom line is managed memory. As shown, native memory is growing disproportionate to managed memory. This indicates a leak in native memory. Actually, this is true. The Web application is calling a COM component, which is native code. The COM component periodically allocates memory that is never freed.

Performance Monitor graph of native versus managed memory.

Figure 9-5. Performance Monitor graph of native versus managed memory.

These are the steps to create the graph shown in 9-5:

  1. Launch the Web application.

  2. Start the Reliability and Performance Monitor from Administrator tools in the Control Panel.

  3. The left pane of the Reliability And Performance Monitor is a tree control. The top node is labeled Reliability And Performance. Open the Monitoring Tools folder, and select Performance Monitor.

  4. The right window is the graphing pane. On the toolbar, if not already selected, select View Current Activity. This is the first button on the toolbar.

  5. Click the down triangle of the Change Graph Type button, which is the third button on the toolbar. Select Line as the type of graph.

The following are the steps to plot native and managed memory on the graph.

  1. If there are counters already being plotted on the line graph, click the X on the toolbar to remove each line.

  2. To add a counter for managed memory, click the + button on the toolbar. The Add Counters dialog box will appear. Expand the .NET CLR Memory counters (click the down arrow "v"). From the list, select # Bytes In All Heaps. Finally, choose w3wp as the instance. Add the counter to the graph with the Add button.

  3. To add a counter for native memory, in the list of counters, find and expand the Process counters. Select the Private Bytes counter and w3wp as the instance. Add the counter to the graph with the Add button. Close the Add Counters dialog box.

  4. Perform actions that you suspect cause a memory leak.

  5. Observe the graph. Notice whether the lines are moving proportional to one another.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset