Garbage Collection in VB6 and .NET

I've noticed some confusion amongst VB6 programmers who've moved to .NET regarding garbage collection, so I'd like to explain the differences.

VB6 is built on top of COM.  In COM, each object has a hidden reference count inside it, a count of the number of in scope variables that point to the object.  When you new an object the reference count is set to 1.  If you then assign that variable to another, the reference count is incremented to 2.  As those references go away, either by variables going out of scope or having a different value assigned to them, the reference count is decremented.  When the reference count goes to 0, there is no way for the object to get used and it gets garbage collected at that time.

In .NET, objects do not have a reference count.  Instead, the .NET run time maintains a list of what points to what.  When an object instantiates another object, the .NET run time keeps track of the relationship.  If the object gets passed around, it remembers those relationships also.  Eventually, all the pointers to an object go away.  At that point, unlike VB6, nothing happens; there simply exists an unreferenced object in memory.  At some point, so much garbage (i. e., unreferenced objects) will build up in memory that the .NET run time will decide to track down unreferenced objects and garbage collect them (that's a simplification, but it will serve).

These differences affect how to program.  In VB6, it is common to set a variable to nothing to force the reference count to drop to 0 and cause garbage collection of that object.  This doesn't make sense in .NET.  Setting something to nothing in .NET, assuming there is only 1 reference, simply cause the object to become a candidate for garbage collection at some later, undefined time.  If you find you really need to force garbage collection in .NET there are 2 options:

      1. Refactor your program to keep scopes as narrow as possible
      2. Use the Dispose pattern

Where and how you declare objects affects how long they are in scope.  Shared variables are in scope for the life of the program, member variables for as long as the object exists, and local variables until a function is exited.  Always strive for the narrowest scope, this way object will naturally garbage collect at the best time.

There can be times when you need to release an object at a specific point in a program.  This is done using the Dispose pattern.  See Dispose, Finalization, and Resource Management for a complete discussion.  The Twitter version is that the Dispose pattern lets you tell an object "You're done; release your resources now".  This is not the same as garbage collection; garbage collection still happens later as described above.  If you need to implement Dispose, pay close attention to the details.  I ran into a nasty bug when this wasn't done correctly, which I discussed at Observations on .NET Object Disposal.

The 2 options are not mutually exclusive at all.  #1 should always be done, #2 should be done whenever necessary.

There is an option 3 which should be avoided, calling the Collect method on the GC class.  Performance will suffer by using GC.Collect.

There is an important difference between forcing garbage collection in VB6 by setting a variable to nothing and forcing clean up in .NET by calling Dispose.  In VB6, garbage collection happens only once there is no way for the object to be accessed.  In .NET, as far as the run time is concerned, Dispose is just another function like any other (compilers treat Dispose special, but not the run time).  You can call Dispose no matter how many references exist to an object.  Also, nothing stops you from using an object after it has been disposed.  Whether this "works" depends on the design of the class.  Nonetheless, using an object after it has been disposed is a violation of the pattern.  Future maintainers of the code may assume the pattern has been followed correctly and cause objects to be unusable once disposed.

Quick Database Sanity Check

My project is on the move, literally.  We're migrating from our old data center to a new one; everything is being brought up on new hardware.  Since we're using full and incremental backups, an important sanity check is to make sure all the data has been restored, which is being done using the following query:

select 'select ''' + TABLE_SCHEMA + ''' as TableSchema, ''' + TABLE_NAME + ''' as TableName, count(*) as [Rows] from ' + TABLE_SCHEMA + '.' + TABLE_NAME + ' union' as [SQL] from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'

The query above produces a query.  When run against the AdventureWorks database you get:

select 'Production' as TableSchema, 'ProductProductPhoto' as TableName, count(*) as [Rows] from Production.ProductProductPhoto union -- many rows removed select 'Production' as TableSchema, 'ProductPhoto' as TableName, count(*) as [Rows] from Production.ProductPhoto union

The result isn't perfect.  The last union operator needs to be replaced by an order by:

select 'Production' as TableSchema, 'ProductPhoto' as TableName, count(*) as [Rows] from Production.ProductPhoto order by TableSchema, TableName

When you run the fixed up query you'll get a list of every table in a database along with the number of rows in each table:

image

If there's too many tables to compare by hand, save the results from the source and destination databases to text files and compare using WinMerge.

Upcoming Speaking Engagements

I'll be speaking twice in November, presenting Virtualization for Developers.

On November 8th I'll be one of the many speakers at the Fairfield / Westchester Code Camp, held in Stamford Connecticut at the The University of Connecticut School of Business.  On November 11th, I'll be the speaker for the Northern New Jersey .NET User Group in Parsippany, NJ.

In Virtualization for Developers I cover how developers can leverage three of Microsoft's virtualization technologies: Virtual PC 2007, Virtual Server 2005, and Windows Server 2008 with Hyper-V.  I'll discuss how developers can reduce costs, speed delivery, reduce errors, and create a repeatable process with virtualization.  Topics include:

  • the basics of Virtual PC, Virtual Server, and Hyper-V
  • tips and traps when using virtual machines
  • how to distribute virtual machine images
  • server based solutions using Virtual Server 2005
  • server based solutions using Windows Server 2008 with Hyper-V
  • licensing issues

I hope to see you at either event!

Microsoft SharedView

When I was at Lucent, everybody on the project was colocated in New Jersey, except one guy who was out in the Chicago area.  But he was the most important guy on the project!  We made this work, and one of the reasons was NetMeeting.  But Microsoft can't leave well enough alone.  NetMeeting has been superceded by Windows Meeting Space.  That's great except that Windows Meeting Space is available for Windows Vista only and there is no NetMeeting for Windows Vista.  In other words, if you want to do peer to peer collaboration with a mix of client operating systems, you're out of luck with these 2 programs.

Fortunately, Microsoft has quietly released Microsoft SharedView.  For some oddball reason, this is considered a component of the Microsoft Connect program.  But SharedView isn't in any specific to Microsoft Connect.  Instead, it is a collaboration program similar to NetMeeting and Windows Meeting Space and it runs on both Windows XP and Windows Vista.

SharedView has all the collaboration basics:

  • create a meeting (requires a Windows Live ID)
  • invite others (using any e-mail address)
  • join a meeting
  • share handouts
  • share windows (including the desktop)
  • take control of shared windows
  • chat

Missing in all this is the whiteboard, video, and audio.  I'm not fond of how the handouts work.  When somebody shares a handout, all you can do with it is save it locally.  Things would be much easier if the handout was downloaded and launched using the associated program.

ASP.NET MVC Firestarter in New York City June 7th

Ever since the new ASP.NET MVC framework was announced in October, posts about it have spread about it like wildfire through the .NET blogosphere.  There's usually at least 2-3 MVC stories a day that show up on DotNetKicks.

At the last Philly.NET code camp in January, there was standing room only for the ASP.NET MVC talk (see photo to the right).  Similar crowds have shown up at the HLS DevCon in Atlantic City, Central Jersey .NET & Fairfield/Westchester .NET user groups to hear about it.

With all the buzz going on about the new ASP.NET MVC Framework, I'm happy to announce a one day Firestarter event in NYC covering it on Saturday, June 7th!  Join us for a day in New York City to learn more about the ASP.NET MVC framework and see what everyone is all excited about.

At the ASP.NET MVC Firestarter, we’ll give you a quick tour of the framework, then peel back the layers and dive deeper into how it works.   As part of that, we’ll spend time discussing the design and development practices that lead to the creation of the MVC framework.  By the time you leave, you’ll have enough knowledge to get fired up and start building web applications with it.

clip_image002More Info

When it comes to design patterns, the MVC is the granddaddy of them all.  First described in the late 70s, the MVC pattern remains very popular in the world of web applications today.  

ASP.NET MVC provides a framework that enables you to easily implement the model-view-controller (MVC) pattern for Web applications. This pattern lets you separate applications into loosely coupled, pluggable components for application design, processing logic, and display.
ASP.NET MVC is not a replacement for Webforms. It provides an alternative choice when designing a Web application. Using ASP.NET MVC offers the following advantages:

  • It enables you to achieve and maintain a clear separation of concerns
  • It facilitates test driven development (TDD)
  • It provides more control over the URLs you publish in the application and over the HTML that is emitted by the application

Registration is now open. Don't wait as this will likely fill to capacity quickly:

Register Here!

Lunch will be provided.

Agenda:

· Intro to ASP.NET MVC & .NET 3.0/3.5   9:00-10:30

· Intro to MVC/MVP patterns   10:30-11:30

Lunch 11:30-12

· Intro to Test Driven Development 12:00-1:00

· Routing  1:00-1:30

· Controllers  1:30-2:30

· Break 2:30-2:45

· Views  2:45-4:00

  • Strongly- vs. Weakly-Typed
    • What’s the difference?
    • Why would you choose one over the other
    • Ways to effectively use Weakly-typed
  • UI Helpers
    • Overview of framework helpers
    • Rolling your own
  • View Engines
    • Overview of WebForms ViewEngine
      • File location/mappings
      • Using “standard” ASP.NET stuff:  ASPX, ASCX, Master
  • REST & AJAX – WCF, Dynamic Data, MVC AJAX  4:00-5:00

Observations on .NET Object Disposal

Here's what I've learned in a recent fight with a nasty object disposal bug.

Every .NET developer needs to understand object disposal.  Start with DG Update: Dispose, Finalization, and Resource Management for a complete discussion of the topic.

Carefully implement the pattern.  Here's the bug I had to deal with:

protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // dispose of managed objects // dispose of unmanaged resources } disposed = true; } }

Both the managed objects and unmanaged resources were being disposed of only when disposing was true.  The code should have been:

protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // dispose of managed objects } // dispose of unmanaged resources disposed = true; } }

 

What this bug does is interfere with finalization.  All of an object's resources that haven't already been released should be during finalization.  But, because the unmanaged resources were disposed of only when disposing was true, nothing was disposed of during finalization.

What's unusual about this bug is that you may never notice it or it may cause you to exhaust a resource and prevent your application from running.  If every disposable object is disposed of, then it doesn't matter that finalization doesn't do anything because there wouldn't be anything to do.  But what if you forget to call Dispose?  In that case the unmanaged resources will never be disposed of and you'll have a classic C++ style leak on your hands.

Whenever possible, use a using statement to ensure object disposal.

Note that there was a huge change between Visual C++ 2003 and Visual C++ 2005 regarding object disposal.  See Changes in Destructor Semantics for details.

Vista SP1 Upgrade

I ran the Vista SP1 upgrade on an Asus V1S running Vista Business.  I was having no issues before the upgrade and haven't found any post upgrade.

Microsoft + Yahoo = Bad Idea

Microsoft has bid $44.6 billion for Yahoo.  This is not a good idea because:

  1. Microsoft and Yahoo are both struggling in search because their products are inferior to Google's.  Combining the two companies won't fix this.  Actually, Google is in a very dangerous position.  All Microsoft has to do is come out with a superior product.  Thanks to the zero cost of switching  search providers, Google could face an exodus.  While not an easy task, Microsoft has the resources to make this happen.
  2. Yahoo is not a mining company.  When you buy a company like Yahoo you're mostly buying the workforce.  The only reasonable assumption is that the technical staff is highly anti-Microsoft.  Even with a retention program, people will leave in droves.  Your best people leave (because it's easy for them) while your weak people stay (for the opposite reason).
  3. What is Microsoft going to do with all that non Microsoft technology at Yahoo?  If this comes to pass, hopefully they'll be sensible about this and maximize the return on prior investments.
  4. Microsoft is highly profitable thanks, in large part, to its corporate customers.  Will Yahoo become such a distraction that they'll take their eye off the ball?  Windows, Office, the development tools, and the server products such as SQL Server are all in a strong position; the last thing Microsoft needs is to start losing momentum in those areas.
  5. Microsoft is paying an approximately one third premium for Yahoo based on market pricing.  That's an extra $15 billion for a company in layoff mode.  Even for Microsoft that's real money.  Does that make sense?

Corporate mergers, especially big ones, have a long history not working out the way the suits plan.  Will Microsoft go from powerhouse to lost in the woods?

WCF REST over HTTP Service

I put together a WCF REST over HTTP service and learned a few things along the way.

Sample Project

The best way to learn about WCF REST is to examine the sample project supplied by Microsoft.  This is available at Windows Communication Foundation (WCF) and Windows CardSpace Samples.  Once you unzip the download you'll find C# and VB sample projects at TechnologySamples\Scenario\PoxMessaging.  These simple projects demonstrate everything you need to know.

Creating Your Own Project

The Visual Studio project template for creating a service hosted by IIS isn't grouped with the WCF projects but is with the ASP.NET projects:

create new project

Once you have a project created, just follow the pattern in the sample and you'll quickly be ready to test.

Testing Your Project

The easiest way to test your project is to use Fiddler 2.  Fiddler 2 includes a tab that lets you form and send HTTP requests:

image

Just select your verb (GET, PUT, etc.), enter the service URL, enter your HTTP headers, paste your XML into Request Body, and press Execute!  Content-Type should be text/xml; Fiddler 2 will automatically calculate the Content-Length header for you.  The result will appear in the left pane; you can double click on the line and get a detailed look at the request and response using the Session Inspector.

HTTP Status Code 415 Unsupported Media Type

If you've been following along exactly, your service should be returning a HTTP Status Code 415 Unsupported Media Type.  This is because when the project was created in Visual Studio there was an assumption that SOAP would be used.  Switching to REST means changing the binding in the web.config file:

<system.serviceModel> <services> <service name="MyService.Service" behaviorConfiguration="MyService.Service1Behavior"> <!-- Service Endpoints --> <!-- use webHttpBinding for REST instead of wsHttpBinding --> <endpoint address="" binding="webHttpBinding" contract="MyService.IService">

Note that this page, which is supposed to list all the System-Provided bindings, doesn't mention webHttpBinding.

Dropping a User's Default Database in SQL Server 2005

What happens if you drop a user's default database in SQL Server 2005 and the user then tries to use SQL Server Management Studio?  You get this crystal clear error message:

image

What to do?  If you have another working administrative login, then you simply need to use that to update the properties of the user that can't connect:

image

But what if the user that can't connect is the only administrative user?  In that case, you need to tell SQL Server Management Studio to connect to a different database on startup, which is done using command line options:

"C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\SqlWb.exe" -S SQLSERVER2005 -d master -E

Here's all the command line options:

image

After executing the above command, SQL Server Management Studio will come up without the object explorer (the tree view on the left) open.  But, it will be connected to the master database and will allow you to run queries.  To fix the user login so that the object explorer can be opened, simply run a query to change the user's default database:

sp_defaultdb 'SQLSERVER2005\dbuser', master

You will be then be able to open the object explorer by using File -> Connect Object Explorer...

Appendix - exact message (for search engines):

A connection was successfully established with the server, but then an error occurred during the login process. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.) (Microsoft SQL Server, Error: 233)