• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
CLR Exception Handing And Memory Management
 

CLR Exception Handing And Memory Management

on

  • 4,381 views

clr exception handling and memory manage.

clr exception handling and memory manage.

Statistics

Views

Total Views
4,381
Views on SlideShare
4,375
Embed Views
6

Actions

Likes
4
Downloads
105
Comments
0

2 Embeds 6

http://www.slideshare.net 4
http://www.docseek.net 2

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

CLR Exception Handing And Memory Management CLR Exception Handing And Memory Management Presentation Transcript

  • Effective .NET Framework based Development: Exception Handing and Memory Management Brad Abrams Lead Program Manager Common Language Runtime Team Microsoft Corporation [email_address] http:// blogs.msdn.com /brada
  • Agenda
    • Exception
      • “ Cleaner, more elegant, and wrong.”
      • Raymond Chen ( http:// blogs.msdn.com/oldnewthing / )
    • Memory Management
      • “I'm addicted to deterministic destruction”
      • Chris Sells ( http:// www.sellsbrothers.com / )
  • Exception Handling Questions
    • Throwing an exception
      • What exception to throw?
      • What data to include in the exception?
    • Managing resources
      • What resources need to be cleaned up?
      • When should they be cleaned up?
    • Catching an Exception
      • When to catch an exception?
      • How to report the error?
      • What to do with the control follow: terminate the app, abort the transaction, ignore the exception, disable some functionality, etc.?
  • When to Throw?
    • Exceptions rather than error codes
      • Robust: failures get noticed
    • Your method is defined to do something…
      • If it succeeds in performing its purpose, return
      • If it fails to do what it was written to do, throw an exception
  • What to throw?
    • Use or subclass existing exceptions if at all possible
    • Only create separate classes if you think developers will handle the exception differently
    try { //some operation } catch (FileNotFoundException fe) { //do some set of work } catch (DriveNotFoundException be) { //do some other set of work }
  • Throwing an Exception
    • Do not just map error codes on to a single exception with an error code property ( e.g. , the WMIException)
      • Use separate exception types
    • Error Messages
      • Consider localization
      • Use a complete sentence (end in a period)
      • Don’t expose privacy related information (such as file paths)
  • Performance
    • Minimize the number of exceptions you throw in your API’s success code-paths
      • You don’t pay for exceptions until you throw in managed code
      • Throwing exceptions degrades performance
      • Perf counters tell you exactly how many exceptions your application is throwing
      • Only an issue when using exceptions as control flow
    • Consider providing a way to avoid an exception being thrown
  • Performance (continued) int i; try { i = Int32.Parse(“123”); } catch (FormatException ) { Console.WriteLine (“Invalid”); } int i; if (!Int32.TryParse (“123”, out i)) { Console.Writeline(“Invalid”); }
  • Managing Resources
    • You should use try..finally 10 times as often as try..catch
      • Catches eat exceptions making it hard to debug
      • Finally allows you to clean up, but let the exception continue
  • Managing Resources
    • You may catch exceptions to re-throw them with a clearer name
      • Typical at an “API” boundary
    • Always nest the underlying exception
    • Catch-and-rethrow has many of the benefits as try..finally
        • But, be aware of debugging issues with catch..throw new() and catch..throw;
        • Generally, cleanup code should go in finalizer
    try { . . . } catch (DivisionByZeroException e) { // do clean up work throw new BetterException (message, e); }
  • Catching Exceptions
    • Do not catch and eat exceptions
      • Exceptions should be handled only where there is enough context to do the right thing
      • That generally means exceptions should be caught as high in the application as possible
    • Mistake – catch the exception, report the error and rethrow it.
      • Only catch where you can handle it
    • Mistake – catch the exception, turn it into a bool pass/fail and return the bool 
  • Catching Exceptions
    • Consider including a try/catch at the top of a thread’s stack if the error can be handled properly
      • Unhandled exceptions at the top of the main thread will terminate the app
      • In 2.0, unhandled exceptions at the top of the stack on any thread will terminate the app
        • But avoid catch blocks in finalizers
      • Be aware: In many cases it is “appropriate” to let the app terminate
    • Be aware of (but ignore) exceptions that don’t inherit from System.Exception
      • Allowed in V1.0V1.1, likely addressed in V2.0
  • catch (Exception e) is your friend
    • Myth: Catching Exception is evil
      • This is motivated by a desire to avoid catching low level exceptions such as OutOfMemoryException, and StackOverflowException
    • Do catch every exception you should handle
    • Don’t attempt to catch every exception a method could throw
      • Its ugly, version brittle, and difficult to test
    • Catch what you need to handle, let the rest pass
  • Agenda
    • Exception
      • “ Cleaner, more elegant, and wrong.”
      • Raymond Chen ( http:// blogs.msdn.com/oldnewthing / )
    • Memory Management
      • “I'm addicted to deterministic destruction”
      • Chris Sells ( http:// www.sellsbrothers.com / )
  • Memory Management
    • The GC does an excellent job managing “managed” memory
    • GC doesn’t manage external resources (DB connections, HWnds, etc. )
    • Generational Mark-and-sweep garbage collection means non-deterministic finalization
      • Exact time of finalization is unspecified
      • Order of finalization is unspecified
      • Thread is unspecified
  • Resource Management
    • If you are encapsulating external resources:
      • Add a finalizer (C# destructor) to guarantee the resource will eventually be freed
      • Provide developers an explicit way to free external resources
      • Formalized in the IDisposable interface
        • Signals to users they need to explicitly Dispose of instances
        • Enables C# and VB (2005) using support
  • Finalizers
    • Object.Finalize() is not accessible in C#
    • VERY different than C++’s destructors
    public class Resource { ~Resource() { ... } } public class Resource { protected override void Finalize() { try { ... } finally { base.Finalize(); } } }
  • Finalizers (2)
    • Only implement Finalize on objects that need finalization
      • Finalization is only appropriate for cleanup of unmanaged resources
      • Keeps objects alive an order of magnitude longer
    • Free any external resources you own in your Finalize method
    • Do not throw exceptions in finalizers
      • The rest of your finalizer will not run
    • Check out Critical Finalizers in 2.0
  • Finalizers (3)
    • Do not block or wait in finalizers
      • All finalization for that process could be stopped
    • Only release resources that are held onto by this instance
    • Do not reference other instances
    • Will be called on one or more different threads
  • Dispose Pattern
    • Implement the dispose pattern whenever you have a finalizer
      • Gives developers explicit control
    • Free any disposable resources your type owns in the Dispose() method
      • Not just the external resources
      • Propagate calls to Dispose() through containment hierarchies
  • Dispose Pattern (2)
    • Suppress finalization once Dispose() has been called
    • Dispose() should be callable multiple times without throwing an exception
      • The method will do nothing after the first call
      • After Dispose() is called other methods on the class can throw ObjectDisposedException
    • Do not assume that Dispose() will be called
      • For unmanaged cleanup have a finalizer as well
    • Do call your base class’s Dispose(bool) method if it implements IDisposable
  • Implementing IDisposable public class Resource: IDisposable { private bool disposed = false; pubic int GetValue () { if (disposed) throw new ObjectDisposedException(); // do work } public void Dispose() { if (disposed) return; Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { // Dispose dependent objects disposed = true; } // Free unmanaged resources } ~Resource() { Dispose(false); } }
  • Using Statement
    • Acquire, Execute, Release pattern
    • Works with any IDisposable object
      • Data access classes, streams, text readers and writers, network classes, etc.
    using (Resource res = new Resource()) { res.DoWork(); } Resource res = new Resource(...); try { res.DoWork(); } finally { if (res != null) ((IDisposable)res).Dispose(); }
  • Using Statement
    • Acquire, Execute, Release pattern
    • Works with any IDisposable object
      • Data access classes, streams, text readers and writers, network classes, etc.
    Using res As Resource = New Resource () res.DoWork() End Using Dim res As New Resource() Try res.DoWork() Finally If res IsNot Nothing Then CType(res, IDisposable).Dispose() End If End Try VB 2005
  • Using Statement (2)
    • Can you find the “bug” in this code?
    • Will input and output always be closed?
    static void Copy(string sourceName, string destName) { Stream input = File.OpenRead(sourceName); Stream output = File.Create(destName); byte[] b = new byte[65536]; int n; while ((n = input.Read(b, 0, b.Length)) != 0) { output.Write(b, 0, n); } output.Close(); input.Close(); }
  • Using Statement (3) static void Copy(string sourceName, string destName) { Stream input = File.OpenRead(sourceName); Stream output = File.Create(destName); try { byte[] b = new byte[65536]; int n; while ((n = input.Read(b, 0, b.Length)) != 0) { output.Write(b, 0, n); } } finally { output.Close(); input.Close(); } }
  • Using Statement (4) static void Copy(string sourceName, string destName) { Stream input = File.OpenRead(sourceName); try { Stream output = File.Create(destName); try { byte[] b = new byte[65536]; int n; while ((n = input.Read(b, 0, b.Length)) != 0) { output.Write(b, 0, n); } } finally { output.Close(); } } finally { input.Close(); } }
  • Using Statement (4)
    • Code is correct and much more readable with using statements
    • Types should implement IDisposable to take advantage of this support
    static void Copy(string sourceName, string destName) { using (Stream input = File.OpenRead(sourceName)) using (Stream output = File.Create(destName)) { byte[] b = new byte[65536]; int n; while ((n = input.Read(b, 0, b.Length)) != 0) { output.Write(b, 0, n); } } }
  • Resource Management 2.0 Feature: MemoryPressure
    • GC.AddMemoryPressure ( int pressure )
      • Useful when you have a disproportionate ratio of managed, to unmanaged resources
      • GC alters it’s strategy, to increase the number of collections performed
      • GC.RemoveMemoryPressure when your object is freed, to allow the GC to return to its standard strategy
  • Resource Management 2.0 Feature: MemoryPressure class Bitmap { private long _size; Bitmap (string path ) { _size = new FileInfo(path).Length; GC.AddMemoryPressure(_size); // other work } ~Bitmap() { GC.RemoveMemoryPressure(_size); // other work } }
  • Resource Management 2.0 Feature: HandleCollector
    • HandleCollector keeps track of a limited number of handles
      • typically, unmanaged resource handles: HDCs, HWnds, etc
    • When you allocate a new handle, call Add.
    • When you freeing, call Remove
    • As you add to the collector, it may perform a GC.Collect(), to free existing handles, based on the current count, and the number of resources available
        • name : allows you to track each handle type separately, if needed
        • initialThreshold : the point at which collections should begin being performed
        • maximumThreshold : the point at which collections MUST be performed. This should be set to the maximum number of available handles
    HandleCollector(string name, int initialThreshold, int maximumThreshold);
  • Resource Management 2.0 Feature: HandleCollector static readonly HandleCollector GdiHandleType = new HandleCollector( “GdiHandles”, 10, 50); static IntPtr CreateSolidBrush() { IntPtr temp = CreateSolidBrushImpl(…); GdiHandleType.Add(); return temp; } internal static void DeleteObject(IntPtr handle) { DeleteObjectImpl(handle); GdiHandleType.Remove(); }
  • More Information
    • My Blog: http://blogs.msdn.com/brada
    The SLAR Designing .NET Class Libraries: http://msdn.microsoft.com/netframework/programming/classlibraries/ FxCop is your ally in the fight: http://www.gotdotnet.com/team/fxcop/ .NET Framework Resource Management whitepaper Resource Management with the CLR: The IDisposable Pattern Special thanks to Brian Harry for significant input in the exceptions section Applied Microsoft .NET Framework Programming
  • Back up
  • Intro to Exception Handling in VB
    • VB .NET has structured Exception Handling
        • Try
        • Obj.DoSomeWork
        • Catch e As Exception
        • LogError(e)
        • Finally
        • Obj.Dispose
        • End Try
    • Can “Throw” an exception
      • Throw New System.Exception(“Error Message”)
    • Enhanced Exception object
      • Tracks nested exceptions
      • Provides StackTrace to help pinpoint error
  • On Error vs. Try/Catch/Finally Try '<code that may fail> Catch ex As Exception '<error handling code> Finally '<clean up> End Try fReRaise = False OnError GoTo ErrHandler '<code that may fail> GoTo CleanUp ErrHandler: If '<condition we can handle> Then '<error handling code> Else fReRaise = True End If CleanUp: If fReRaise Then Err.Raise errNum OnError GoTo ErrHandler '<code that may fail> ErrHandler: If '<condition we can handle> Then '<error handling code> fReRaise = False Try '<code that may fail> Else fReRaise = True End If CleanUp: If fReRaise Then Err.Raise errNum Catch ex As Exception '<error handling code> Finally '<clean up>
  • VB 2005 Exception Support
    • Exception Assistant
      • A dialog pops up when an exception occurs in your application that describes the exception type and the common ways reasons for it being thrown. You can set any exception type you like to be a “first chance exception” which would bring up the dialog in the first place it encountered this exception via the DebugàExceptions menus.  
    • Overlapping Exception Warnings
      • VB warns when you’ve caught a supertype exception before its subtype (thus indicating dead code.)
    • IDispose spit
      • Visual Basic will now spit the IDisposable pattern when you type Implements IDispose and commit.  
    • Unhandled Exception event
      • VB now has application events which you can access by opening the app designer, selecting the “view application events” button, and using the drop downs to navigate to the UnhandledException event.
    • Using statement
      • In 2005, VB will support it too.
    • Application tracing
      • VB now supports an extremely easy way to do application logging. Just type My.Application.Log.WriteException() and go from there…
  • Using Exceptions: Creating new Exceptions (continued)
    • Every exception should have at least the top three constructors
    public class XxxException : YyyException { public XxxException () {} public XxxException (string message) {} public XxxException (string message, Exception inner) {} protected XxxException ( SerializationInfo info, StreamingContext context) {} }
    • Note: making an exception fully serializable implies a little more work…
  • Using Exceptions: Bad Practice
    • ArgumentNullException does not follow this pattern
    • Justification: Argument names are much more common than message
    public class ArgumentNullException : ArgumentException { public ArgumentNullException () {} public ArgumentNullException (string paramName) {} public ArgumentNullException (string paramName, string message) {} }
  • Using Exceptions: Bad Practice
    • Result: Habit wins out and people commonly type:
    throw new ArgumentNullException (&quot;the value must pass an employee name&quot;); throw new ArgumentNullException (&quot;Name&quot;, &quot;the value must pass an employee name&quot;); Unhandled Exception: System.ArgumentNullException: Value cannot be null. Parameter name: the value must pass an employee name
    • Rather than:
    • We end up with odd error messages such as:
    • Lesson: Just follow the pattern!