C# and GC.KeepAlive()

Today, while browsing some C++/CLI code, I stumbled upon several calls to GC.KeepAlive(someObj).

Immediately I thought memory leak – because I thought KeepAlive() would keep the object alive indefinitely.

Fortunately, this turned out to be wrong, though.

After reading the documentation of GC.KeepAlive() (couldn’t really figure it out), I did some decompiling and found out that GC.KeepAlive() looks like this:

1
2
3
4
[MethodImpl(MethodImplOptions.NoInlining)]
public static void KeepAlive(object obj)
{
}

It just does nothing. So what’s its purpose?

It’s there to fake an access to a variable.

Why? The .NET garbage collector may collect a variable directly after its last use – and not necessarily, contrary to common belief, at the end of the variable’s scope.

Consider this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class SomeClass
{
  // This field is initialized somewhere 
  // in the constructor (not shown here).
  public SomeOtherClass Value;
 
  ...
}
 
...
 
void MyMethod()
{
  SomeClass obj = new SomeClass();
  SomeOtherMethod(obj.Value);
  YetAnotherMethod();
  // obj still alive here? Possibly not.
}

The garbage collector may collect obj just after the runtime has retrieved obj.Value (line 15), i.e. before SomeOtherMethod() is even called.

Note: The exact line where obj will be marked for collection is up to the JIT compiler. The behavior describe above seems to be called “lookahead optimization”.

Usually this optimization not a problem. It becomes a problem, however, if SomeClass has a finalizer:

1
2
3
4
5
6
7
8
9
10
11
class SomeClass
{
  public SomeOtherClass Value;
 
  ~SomeClass()
  {
     // "Value" can't be used anymore 
     // after Dispose() has been called.
     this.Value.Dispose();
  }
}

So, if obj‘s finalizer is executed before SomeOtherMethod() is called, SomeOtherMethod() won’t be able to use obj.Value anymore.

To solve this problem, add GC.KeepAlive() after the call to SomeOtherMethod(), like this (line 5):

1
2
3
4
5
6
7
void MyMethod()
{
  SomeClass obj = new SomeClass();
  SomeOtherMethod(obj.Value);
  GC.KeepAlive(obj);
  YetAnotherMethod();
}

This way, the garbage collector won’t collect obj (and thus run its finalizer) before line 5 has been reached.

Notes:

  • The implementation of the finalizer of SomeClass is flawed – as the examples in this article show. The user shouldn’t need to worry about Value being disposed too early.

    • Rule of thumb: A finalizer should only dispose the resources of its own class, not resources of some member (by calling Dispose() on members).
    • The problem with the finalizer persists if Value is an unmanaged resource/pointer that’s being passed to SomeOtherMethod(). This is always possible in C++/CLI. In C# Value could be of type IntPtr.
    • In the examples above, consider implementing and using IDisposable for SomeClass instead of GC.KeepAlive(), if you need a finalizer.
    • You still need to use GC.KeepAlive() if you can’t change the implementation of SomeClass.
  • Using GC.KeepAlive() is like using GCHandle, just more light-weight and faster.
  • GC.KeepAlive() only works because it can’t be inlined by the compiler (MethodImplOptions.NoInlining).

Passing native pointers across C++/CLI assembly boundaries

C++/CLI allows you to mix native C++ code with managed .NET code (which is extremly nice). Mixing such code also allows you to create methods in a .NET class that take or return pointers to native (C++) classes. Unfortunately, this doesn’t work out of the box across assemblies (read: DLLs). If you define a .NET class in one assembly and this class has a method that returns a pointer, you may not be able to use this method from within another C++/CLI assembly.

This article describes the problem and shows solutions.

Read more →

Ping/Identify Computers By Computer Name In Windows

Some routers (like the Fritz!Box) provide DNS names for all computers in a network – based on the computer names.

For example, in my network I have a Windows computer called Beeblebrox and a Linux computer called Marvin. They can be reached by name through beeblebrox.fritz.box and marvin.fritz.box respectively.

When I’m on my Linux computer I can just type ping beeblebrox and will ping my Windows computer.

When I’m on my Windows computer on the other hand, this doesn’t work – at least not out of the box.

C:\Users\manski>ping marvin
Ping request could not find host marvin. Please check the name and try again.

To make this work, …

  1. go the Control Panel, then System.
  2. In the left sidebar click on Advanced system settings.
  3. The dialog “System Properties” will open. Choose the tab Computer Name and click on Change….
  4. The dialog “Computer Name/Domain Changes” will open. Here, click on More…
  5. Enter the DNS suffix in the box.
  6. Confirm all dialogs with “OK” and restart the computer afterwards.

set-domain-suffix.png

Now you can ping/identify any computer on the same network by using just its name:

C:\Users\manski>ping marvin

Pinging marvin.fritz.box [192.168.42.5] with 32 bytes of data:
Reply from 192.168.42.5: bytes=32 time=2ms TTL=64
Reply from 192.168.42.5: bytes=32 time=2ms TTL=64

Windows Setup, Boot Manager, And Multiple Disks

Although Windows Setup has evolved since the days of Windows 95, it sometimes is still a real pain in the ass.

Today, I spent the whole morning figuring out why Windows Setup always placed the Windows boot manager on a separate drive – and not on the drive I was installing Windows onto.

The “easiest” solution would be to unplug all other drives, install Windows, and then replug all drives. But since I’m a engineer I wanted to find out the real cause of the problem.

Turns out, the root problem is the BIOS’ boot order (a.k.a. boot sequence). A computer’s BIOS has a boot order list which basically defines from which device (hard disk, CD drive) to boot. If the BIOS can’t boot from the first device, it tries the second one, and so on.

The BIOS usually lets you define this order. Either all devices are in one big list, or each device type (CD drives, hard disks) has its own list.

Example of a boot order menu item in a BIOS

Now, when you install Windows, the setup asks the BIOS for this list. And no matter what you do, Windows Setup will always install the boot manager on the first hard disk in this boot order list.

In particular, the disk on which you want to install Windows has no influence on where the boot manager is being installed.

So, the only way to influence the location of the boot manager is to change to boot order in the BIOS.

Side note: New devices are usually added to the end of the boot order list. So if you have multiple hard drives and replace one (e.g. because the old one was broken or too small), the new drive may end up at the end of the list – and not at the position where the replaced drive was before; thus messing up the boot order.

Determining the Boot Manager Partition

So, how can one determine the location of where boot manager is installed?

From Windows Setup

Determining on which drive Windows Setup will install the boot manager onto is almost impossible from Windows Setup itself.

The only hint you get, is if:

  • your installation disk has no partitions (i.e. is empty) …
  • .. and then you can create a partition on this disk.

In this case Windows Setup will show you a dialog reading:

To ensure that all Windows features work correctly, Windows might create additional partitions for system files.

If this happens and you click on “OK”, Windows Setup will automatically create a partition called “System Reserved” where it’ll install the boot manager.

boot-manager-in-windows-setup.jpg

If this doesn’t happen the boot manager may or may not be installed in the correct location. If this is the case, you can only check the location after Windows has been installed.

From Windows

To determine the partition where the boot manager is installed, go to:

Control Panel > Administrative Tools > Computer Management > Disk Management

The partition where the boot manager is installed has the word System in its status.

sytem-partition.jpg

Windows Update Progress Bar Fail

If you have some progress you can use a progress bar to show this progress.

So, if you copy some files and have already copied about 60%, you may see something like this:

Progress bar showing copy progress of some files

Knowing this, what’s wrong with this image?

Indeterminate progress bar on download progress in Windows Update

Why the heck do I get an indeterminate progress bar for a download progress. Hell, there’s even a percentage displayed for the download.