Presentation is loading. Please wait.

Presentation is loading. Please wait.

Effective.NET Framework based Development: Exception Handing and Memory Management Effective.NET Framework based Development: Exception Handing and Memory.

Similar presentations


Presentation on theme: "Effective.NET Framework based Development: Exception Handing and Memory Management Effective.NET Framework based Development: Exception Handing and Memory."— Presentation transcript:

1 Effective.NET Framework based Development: Exception Handing and Memory Management Effective.NET Framework based Development: Exception Handing and Memory Management Brad Abrams Lead Program Manager Common Language Runtime Team Microsoft Corporation brada@microsoft.combrada@microsoft.com http://blogs.msdn.com/bradahttp://blogs.msdn.com/brada

2 Agenda Exception Exception “Cleaner, more elegant, and wrong.” Cleaner, more elegant, and wrong.”Cleaner, more elegant, and wrong.” Raymond Chen ( http://blogs.msdn.com/oldnewthing/) http://blogs.msdn.com/oldnewthing/ Memory Management Memory Management “I'm addicted to deterministic destruction” “I'm addicted to deterministic destruction” Chris Sells ( http://www.sellsbrothers.com/) http://www.sellsbrothers.com/

3 Exception Handling Questions Throwing an exception Throwing an exception What exception to throw? What exception to throw? What data to include in the exception? What data to include in the exception? Managing resources Managing resources What resources need to be cleaned up? What resources need to be cleaned up? When should they be cleaned up? When should they be cleaned up? Catching an Exception Catching an Exception When to catch an exception? When to catch an exception? How to report the error? 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.? What to do with the control follow: terminate the app, abort the transaction, ignore the exception, disable some functionality, etc.?

4 When to Throw? Exceptions rather than error codes Exceptions rather than error codes Robust: failures get noticed Robust: failures get noticed Your method is defined to do something… Your method is defined to do something… If it succeeds in performing its purpose, return If it succeeds in performing its purpose, return If it fails to do what it was written to do, throw an exception If it fails to do what it was written to do, throw an exception

5 What to throw? Use or subclass existing exceptions if at all possible Use or subclass existing exceptions if at all possible Only create separate classes if you think developers will handle the exception differently 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 }

6 Throwing an Exception Do not just map error codes on to a single exception with an error code property (e.g., the WMIException) Do not just map error codes on to a single exception with an error code property (e.g., the WMIException) Use separate exception types Use separate exception types Error Messages Error Messages Consider localization Consider localization Use a complete sentence (end in a period) Use a complete sentence (end in a period) Don’t expose privacy related information (such as file paths) Don’t expose privacy related information (such as file paths)

7 Performance Minimize the number of exceptions you throw in your API’s success code-paths 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 You don’t pay for exceptions until you throw in managed code Throwing exceptions degrades performance Throwing exceptions degrades performance Perf counters tell you exactly how many exceptions your application is throwing Perf counters tell you exactly how many exceptions your application is throwing Only an issue when using exceptions as control flow Only an issue when using exceptions as control flow Consider providing a way to avoid an exception being thrown Consider providing a way to avoid an exception being thrown

8 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”); }

9 Managing Resources You should use try..finally 10 times as often as try..catch You should use try..finally 10 times as often as try..catch Catches eat exceptions making it hard to debug Catches eat exceptions making it hard to debug Finally allows you to clean up, but let the exception continue Finally allows you to clean up, but let the exception continue

10 Managing Resources You may catch exceptions to re-throw them with a clearer name You may catch exceptions to re-throw them with a clearer name Typical at an “API” boundary Typical at an “API” boundary Always nest the underlying exception Always nest the underlying exception Catch-and-rethrow has many of the benefits as try..finally Catch-and-rethrow has many of the benefits as try..finally But, be aware of debugging issues with catch..throw new() and catch..throw; But, be aware of debugging issues with catch..throw new() and catch..throw; Generally, cleanup code should go in finalizer Generally, cleanup code should go in finalizer try {... } catch (DivisionByZeroException e) { // do clean up work throw new BetterException (message, e); }

11 Catching Exceptions Do not catch and eat exceptions Do not catch and eat exceptions Exceptions should be handled only where there is enough context to do the right thing 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 That generally means exceptions should be caught as high in the application as possible Mistake – catch the exception, report the error and rethrow it. Mistake – catch the exception, report the error and rethrow it. Only catch where you can handle it Only catch where you can handle it Mistake – catch the exception, turn it into a bool pass/fail and return the bool Mistake – catch the exception, turn it into a bool pass/fail and return the bool

12 Catching Exceptions Consider including a try/catch at the top of a thread’s stack if the error can be handled properly 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 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 In 2.0, unhandled exceptions at the top of the stack on any thread will terminate the app But avoid catch blocks in finalizers But avoid catch blocks in finalizers Be aware: In many cases it is “appropriate” to let the app terminate 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 Be aware of (but ignore) exceptions that don’t inherit from System.Exception Allowed in V1.0\V1.1, likely addressed in V2.0 Allowed in V1.0\V1.1, likely addressed in V2.0

13 catch (Exception e) is your friend Myth: Catching Exception is evil Myth: Catching Exception is evil This is motivated by a desire to avoid catching low level exceptions such as OutOfMemoryException, and StackOverflowException This is motivated by a desire to avoid catching low level exceptions such as OutOfMemoryException, and StackOverflowException Do catch every exception you should handle Do catch every exception you should handle Don’t attempt to catch every exception a method could throw Don’t attempt to catch every exception a method could throw Its ugly, version brittle, and difficult to test Its ugly, version brittle, and difficult to test Catch what you need to handle, let the rest pass Catch what you need to handle, let the rest pass

14 Agenda Exception Exception “Cleaner, more elegant, and wrong.” Cleaner, more elegant, and wrong.”Cleaner, more elegant, and wrong.” Raymond Chen ( http://blogs.msdn.com/oldnewthing/) http://blogs.msdn.com/oldnewthing/ Memory Management Memory Management “I'm addicted to deterministic destruction” “I'm addicted to deterministic destruction” Chris Sells ( http://www.sellsbrothers.com/) http://www.sellsbrothers.com/

15 Memory Management The GC does an excellent job managing “managed” memory The GC does an excellent job managing “managed” memory GC doesn’t manage external resources (DB connections, HWnds, etc.) GC doesn’t manage external resources (DB connections, HWnds, etc.) Generational Mark-and-sweep garbage collection means non-deterministic finalization Generational Mark-and-sweep garbage collection means non-deterministic finalization Exact time of finalization is unspecified Exact time of finalization is unspecified Order of finalization is unspecified Order of finalization is unspecified Thread is unspecified Thread is unspecified

16 Resource Management If you are encapsulating external resources: If you are encapsulating external resources: Add a finalizer (C# destructor) to guarantee the resource will eventually be freed Add a finalizer (C# destructor) to guarantee the resource will eventually be freed Provide developers an explicit way to free external resources Provide developers an explicit way to free external resources Formalized in the IDisposable interface Formalized in the IDisposable interface Signals to users they need to explicitly Dispose of instances Signals to users they need to explicitly Dispose of instances Enables C# and VB (2005) using support Enables C# and VB (2005) using support

17 Finalizers Object.Finalize() is not accessible in C# Object.Finalize() is not accessible in C# VERY different than C++’s destructors VERY different than C++’s destructors public class Resource { ~Resource() {... } public class Resource { ~Resource() {... } public class Resource { protected override void Finalize() { try {... } finally { base.Finalize(); } public class Resource { protected override void Finalize() { try {... } finally { base.Finalize(); }

18 Finalizers (2) Only implement Finalize on objects that need finalization Only implement Finalize on objects that need finalization Finalization is only appropriate for cleanup of unmanaged resources Finalization is only appropriate for cleanup of unmanaged resources Keeps objects alive an order of magnitude longer Keeps objects alive an order of magnitude longer Free any external resources you own in your Finalize method Free any external resources you own in your Finalize method Do not throw exceptions in finalizers Do not throw exceptions in finalizers The rest of your finalizer will not run The rest of your finalizer will not run Check out Critical Finalizers in 2.0 Check out Critical Finalizers in 2.0

19 Finalizers (3) Do not block or wait in finalizers Do not block or wait in finalizers All finalization for that process could be stopped All finalization for that process could be stopped Only release resources that are held onto by this instance Only release resources that are held onto by this instance Do not reference other instances Do not reference other instances Will be called on one or more different threads Will be called on one or more different threads

20 Dispose Pattern Implement the dispose pattern whenever you have a finalizer Implement the dispose pattern whenever you have a finalizer Gives developers explicit control Gives developers explicit control Free any disposable resources your type owns in the Dispose() method Free any disposable resources your type owns in the Dispose() method Not just the external resources Not just the external resources Propagate calls to Dispose() through containment hierarchies Propagate calls to Dispose() through containment hierarchies

21 Dispose Pattern (2) Suppress finalization once Dispose() has been called Suppress finalization once Dispose() has been called Dispose() should be callable multiple times without throwing an exception Dispose() should be callable multiple times without throwing an exception The method will do nothing after the first call The method will do nothing after the first call After Dispose() is called other methods on the class can throw ObjectDisposedException After Dispose() is called other methods on the class can throw ObjectDisposedException Do not assume that Dispose() will be called Do not assume that Dispose() will be called For unmanaged cleanup have a finalizer as well For unmanaged cleanup have a finalizer as well Do call your base class’s Dispose(bool) method if it implements IDisposable Do call your base class’s Dispose(bool) method if it implements IDisposable

22 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); } 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); }

23 Using Statement Acquire, Execute, Release pattern Acquire, Execute, Release pattern Works with any IDisposable object Works with any IDisposable object Data access classes, streams, text readers and writers, network classes, etc. Data access classes, streams, text readers and writers, network classes, etc. using (Resource res = new Resource()) { res.DoWork(); } using (Resource res = new Resource()) { res.DoWork(); } Resource res = new Resource(...); try { res.DoWork(); } finally { if (res != null) ((IDisposable)res).Dispose(); } Resource res = new Resource(...); try { res.DoWork(); } finally { if (res != null) ((IDisposable)res).Dispose(); }

24 Using Statement Acquire, Execute, Release pattern Acquire, Execute, Release pattern Works with any IDisposable object Works with any IDisposable object Data access classes, streams, text readers and writers, network classes, etc. Data access classes, streams, text readers and writers, network classes, etc. Using res As Resource = New Resource () res.DoWork() End Using 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 Dim res As New Resource() Try res.DoWork() Finally If res IsNot Nothing Then CType(res, IDisposable).Dispose() End If End Try

25 Using Statement (2) Can you find the “bug” in this code? Can you find the “bug” in this code? Will input and output always be closed? 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(); } 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(); }

26 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(); } 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(); }

27 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(); } 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(); }

28 Using Statement (4) Code is correct and much more readable with using statements Code is correct and much more readable with using statements Types should implement IDisposable to take advantage of this support 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); } 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); }

29 Resource Management 2.0 Feature: MemoryPressure GC.AddMemoryPressure ( int pressure ) GC.AddMemoryPressure ( int pressure ) Useful when you have a disproportionate ratio of managed, to unmanaged resources 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 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 GC.RemoveMemoryPressure when your object is freed, to allow the GC to return to its standard strategy

30 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 } class Bitmap { private long _size; Bitmap (string path ) { _size = new FileInfo(path).Length; GC.AddMemoryPressure(_size); // other work } ~Bitmap() { GC.RemoveMemoryPressure(_size); // other work }

31 Resource Management 2.0 Feature: HandleCollector HandleCollector keeps track of a limited number of handles HandleCollector keeps track of a limited number of handles typically, unmanaged resource handles: HDCs, HWnds, etc typically, unmanaged resource handles: HDCs, HWnds, etc When you allocate a new handle, call Add. When you allocate a new handle, call Add. When you freeing, call Remove 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 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);

32 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(); } 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(); }

33 More Information My Blog: http://blogs.msdn.com/brada My Blog: http://blogs.msdn.com/bradahttp://blogs.msdn.com/brada The SLAR Designing.NET Class Libraries: http://msdn.microsoft.com/netframework/programming/classlibraries/ http://msdn.microsoft.com/netframework/programming/classlibraries/ FxCop is your ally in the fight: http://www.gotdotnet.com/team/fxcop/http://www.gotdotnet.com/team/fxcop/.NET Framework Resource Management.NET Framework Resource Management whitepaper Resource Management with the CLR: The IDisposable Pattern Special thanks to Brian Harry for significant input in the exceptions sectionBrian Harry Applied Microsoft.NET Framework Programming

34 Back up

35 Intro to Exception Handling in VB VB.NET has structured Exception Handling VB.NET has structured Exception HandlingTryObj.DoSomeWork Catch e As Exception LogError(e)FinallyObj.Dispose End Try Can “Throw” an exception Can “Throw” an exception Throw New System.Exception(“Error Message”) Enhanced Exception object Enhanced Exception object Tracks nested exceptions Tracks nested exceptions Provides StackTrace to help pinpoint error Provides StackTrace to help pinpoint error

36 Try ' Catch ex As Exception ' Finally ' End Try fReRaise = False OnError GoTo ErrHandler ' GoTo CleanUp ErrHandler: If ' Then ' Else fReRaise = True End If CleanUp: If fReRaise Then Err.Raise errNum On Error vs. Try/Catch/Finally OnError GoTo ErrHandler ' ErrHandler: If ' Then ' fReRaise = False Try ' Else fReRaise = True End If CleanUp: If fReRaise Then Err.Raise errNum Catch ex As Exception ' Finally '

37 VB 2005 Exception Support Exception Assistant 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. 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 Overlapping Exception Warnings VB warns when you’ve caught a supertype exception before its subtype (thus indicating dead code.) VB warns when you’ve caught a supertype exception before its subtype (thus indicating dead code.) IDispose spit IDispose spit Visual Basic will now spit the IDisposable pattern when you type Implements IDispose and commit. Visual Basic will now spit the IDisposable pattern when you type Implements IDispose and commit. Unhandled Exception event 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. 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 Using statement In 2005, VB will support it too. In 2005, VB will support it too. Application tracing Application tracing VB now supports an extremely easy way to do application logging. Just type My.Application.Log.WriteException() and go from there… VB now supports an extremely easy way to do application logging. Just type My.Application.Log.WriteException() and go from there…

38 Using Exceptions: Creating new Exceptions (continued) Every exception should have at least the top three constructors 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… Note: making an exception fully serializable implies a little more work…

39 Using Exceptions: Bad Practice ArgumentNullException does not follow this pattern ArgumentNullException does not follow this pattern Justification: Argument names are much more common than message 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) {} }

40 Using Exceptions: Bad Practice Result: Habit wins out and people commonly type: Result: Habit wins out and people commonly type: throw new ArgumentNullException ("the value must pass an employee name"); throw new ArgumentNullException ("Name", "the value must pass an employee name"); 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!


Download ppt "Effective.NET Framework based Development: Exception Handing and Memory Management Effective.NET Framework based Development: Exception Handing and Memory."

Similar presentations


Ads by Google