Okay this is a really weird one! When you install Service Pack 2 on Windows Server 2003 you can no longer connect using MSTSC via Terminal Services (TS)/Remote Desktop(RDP) with a 24-bit color setting. For the customer I was working with this meant that the applications they are hosting on those servers did not look good at all over this down graded connection. For them it meant a blocker to upgrading to SP2. This has gotten more important recently because Service Pack 1 for Windows Server 2003 is about to be out of support.
So a hunt ensued for how to get this working. It turns out that there was a bug in Service Pack 2 that disable some of these higher bit rates. The bug was corrected in KB – 942610 although this was not apparent that it applied to my problem since the description was different. However it turns out that the same underlying issue was causing both problems. A couple of other changes needed to happen and then everything was working. Here are the steps that I came up with to take a Win2K3 SP2 box and enable 24-bit Color Connections:
Important This section, method, or task contains steps that tell you how to modify the registry. However, serious problems might occur if you modify the registry incorrectly. Therefore, make sure that you follow these steps carefully. For added protection, back up the registry before you modify it. Then, you can restore the registry if a problem occurs. For more information about how to back up and restore the registry, click the following article number to view the article in the Microsoft Knowledge Base: 322756 How to back up and restore the registry in Windows
Important This section, method, or task contains steps that tell you how to modify the registry. However, serious problems might occur if you modify the registry incorrectly. Therefore, make sure that you follow these steps carefully. For added protection, back up the registry before you modify it. Then, you can restore the registry if a problem occurs. For more information about how to back up and restore the registry, click the following article number to view the article in the Microsoft Knowledge Base:
322756 How to back up and restore the registry in Windows
Hope this helps!
Thanks, Zach
In your Workflow application (more exactly in the host of your workflow application) never use anonymous delegate like that :
AutoResetEvent waitHandle = new AutoResetEvent(false); . . . workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { waitHandle.Set(); };
The code above is very common and works correctly at least most of the time... Actually when you do something like that, then after a few iterations (if you always keep the same instance of the Workflow runtime as it should be the case) you will notice the number of AutoResetEvent object always increases until eventually an Out Of Memory exception is raised.
If you take a debugger like Windbg and display the chain of reference for one particular instance of the AutoResetEvent class you will have an output similar to the following:
DOMAIN(00000000002FF7E0):HANDLE(WeakSh):c1580:Root: 00000000029126e8(System.Workflow.Runtime.WorkflowRuntime)-> 000000000296e500(System.EventHandler`1[[System.Workflow.Runtime.WorkflowTerminatedEventArgs, System.Workflow.Runtime]])-> 0000000002966970(System.Object[])-> 00000000029570e0(System.EventHandler`1[[System.Workflow.Runtime.WorkflowTerminatedEventArgs, System.Workflow.Runtime]])-> 0000000002957038(TestLeakWorkflow.Program+<>c__DisplayClass2)-> 0000000002957050(System.Threading.AutoResetEvent)
If now you dump the instance of TestLeakWorkflow.Program+<>c__DisplayClass2 you will have the following output :
MT Field Offset Type VT Attr Value Name 000007fef70142d0 4000003 8 AutoResetEvent 0 instance 0000000002957050 waitHandle
What does it tell us? This class TestLeakWorkflow.Program+<>c__DisplayClass2 contains one property of type AutoResetEvent. In our case this property has a strong reference to the object of type AutoResetEvent, consequently the final object is still referenced and remains logically memory.
Why that? Well the purpose of this entry is not to give details about anonymous delegate, but basically there is nothing magic with anonymous delegate, and for the delegate function to access to variable which are not in its scope (look closer, the waitHandle object is not in the scope of the delegate function but still it can access to it) a mechanism is needed. For that, the compiler creates an intermediate class with one property per object which is used in the function delegate but which is normally not in its scope, the delegate function is just a member function of this class; it can then easily access to the properties of the class.
What if you use hundred of objects in the anonymous delegate, objects which are normally not in the scope of the delegate? Well, you will have an intermediate class with hundred of attributes. The instances of the class will then reference the real objects...
Why is that a problem? Well, again look closely? How can you get rid of this instance? You have to remove the reference to the delegate but you cannot (not with the syntax used above), it means the intermediary class and more problematically the final object are still referenced and remain in memory.
To better understand the problem, let’s now study the fragment below, this is a quite classical fragment of code that you will often find in multiple blogs (I know it’s from one of this blog that we have got the code that have been implanted in production and on which I have spent hours debugging to understand why the portal was dying after several hours) :
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(MyASPNetSequencialWorkFlow)); instance.Start(); workflowRuntime.WorkflowCompleted += delegate(object o, WorkflowCompletedEventArgs e1) { if (e1.WorkflowInstance.InstanceId == instance.InstanceId) { ...
Yes you got it, in this case this is the Workflow instance which will be referenced and which will stay in memory. Considering the fact that in a web application host (as well as in Windows service host) the WorkflowRuntime is a long live object, you will for sure have an Out Of Memory exception.
What do then? Well a code like the one below is definitely better :
EventHandler<WorkflowTerminatedEventArgs> terminatedHandler = null; EventHandler<WorkflowCompletedEventArgs> completedHandler = null; terminatedHandler = delegate(object sender, WorkflowTerminatedEventArgs e) { if (instance.InstanceId == e.WorkflowInstance.InstanceId) { Console.WriteLine(e.Exception.Message); workflowRuntime.WorkflowCompleted -= completedHandler; workflowRuntime.WorkflowTerminated -= terminatedHandler; waitHandle.Set(); } }; workflowRuntime.WorkflowTerminated += terminatedHandler; completedHandler = delegate(object sender, WorkflowCompletedEventArgs e) { if (instance.InstanceId == e.WorkflowInstance.InstanceId) { WorkflowInstance b = instance; workflowRuntime.WorkflowCompleted -= completedHandler; workflowRuntime.WorkflowTerminated -= terminatedHandler; waitHandle.Set(); } }; workflowRuntime.WorkflowCompleted += completedHandler;
You again have to be prudent, you must remove all the handlers, if at the end WorkflowCompleted Handler is executed, WorkflowTerminated handler will never be executed hence the all the handler are removed in both delegates.
Thanks, Fabrice
Today I was working on a problem that we thought was network related. That meant it was time to try out some of those NetMon skills. NetMon is the Microsoft Network Packet Capture and Analysis tool that is similar to WireShark/ethereal and can the current 3.2 version can be download for free from here - http://www.microsoft.com/downloads/details.aspx?FamilyID=f4db40af-1e08-4a21-a26b-ec2f4dc4190d&DisplayLang=en
For the longest time I am a lot of my colleagues used WireShark/ethereal to do network captures. However Netmon has come a long way and I really am a big fan of it now.
Back to my problem today. We were dealing with a Web Server that has a decent amount of traffic and problem that occurred intermittently. I first started just capturing with the UI but quickly saw the memory grow and the box slow down a bit. I did not need to see the traffic going by I just needed to do a capture. This lead me to the NMCAP tool that ships with NetMon. This is a basic command line tool that allows you do to do captures.
So I started capturing and by default if you use the *.chn extension on the file name you specify it will create 20 MB CAP files with your network data. This as great. I could easily filter out the ones I did not want while I awaited the problem.
Finally the problem reproduced and now I was ready to analyze. I opened the trace closest to when the problem occurred and began working through the trace. I quickly found some conversations that I was interested but – Where was the beginning? Where was the end?
The answer to this – In some of the other traces!
Now I had 3, 4, 5, 6 different traces open and that was no good. I quickly wanted to be able to combine the 6 or 10 traces that I was interested it. I found out that the same NMCAP tool can easily do this. All you have to do is use the /InputCapture param. You end up with a command line like this:
namcap /InputCapture Trace1.cap Trace2.cap Trace3.cap /capture /file Trace.cap:500M
This was a life saver so I thought I would pass it along! Enjoy and have a great weekend.
Thanks,
Zach