Introduction
Around mid-nineties, the migration from 16-bit systems to 32-bit systems was in full swing. The benefits were very clear, but unfortunately, the move caused hair pulling for many .NET developers as they needed to learn new memory models, new API functions and changed pointer arithmetic.In the present day, we are facing a similar situation when moving from 32-bit to 64-bit systems. Luckily, this change is much more modest, and for many applications, not much needs to be done to keep the 32-bit application happily running on a 64-bit system. Because of the virtual machine technology and the way CLR (Common Language Runtime) is written, your .NET application might even automatically convert itself to a 64-bit application.
However, to break through the 2 GB memory limit or use native code or components outside the managed code barrier, you need to pay attention to the way you write your code.
In this article, you are going to learn the basics of moving your ,.NET & C# applications to 64-bit systems. Along the way, you are also going to learn a bit about memory management, code compatibility, and discover migration tips.
Note that this article uses the terms "32-bit system" and "64-bit system" in a specific manner. Here, these terms are used to indicate the operating system bitness, and not the bits supported by the computer hardware. Technically speaking, it is perfectly possible to install a 32-bit operating system on a PC capable of running 64-bit operating systems. In this article, bits refer to the installed architecture of the operating system.
The basics of application compatibility
Because the number of available Windows applications is enormous, a new Windows version cannot simply stop running older applications. The same applies when you migrate upwards in the number of bits in the system. Thus, a regular 32-bit application can in many cases continue to run on a 64-bit system without changes to the application code.When installing, for instance, a 64-bit Windows 7, the DLLs that implement the Windows programming interfaces are natively 64-bit. This might lead you to think that 32-bit applications would not be able to run, but in fact they can. This is because the operating system supports a feature called Windows-on-Windows (WoW64), which simulates a 32-bit Windows installation inside a 64-bit OS. Because of this, all the 32-bit applications think that they are running just as before, and in many cases work right out of the box.
About memory allocation limits in .NET applications
One of the primary reasons of moving to 64-bit architecture is the ability to use more memory. By default, 32-bit Windows applications are limited to 2 GB of memory (virtual address space). For many applications, this is enough, but high-end applications or those manipulating large amounts of data (be it images, video, statistical input or SQL databases) can run faster, if they can process larger amounts of memory without dividing the data into smaller chunks.For .NET developers, understanding low-level memory management hasn't been necessary, as the CLR handles all the rudimentary work. Instead, it is enough to simply instantiate objects, and let the runtime handle the rest. The same applies in 64-bit systems, but even if you are running your .NET application on a 64-bit system, you cannot simply start allocating huge, multi-gigabyte arrays right away.
Instead, there's a limit on the size of any single object in .NET. For instance, you cannot allocate a byte array larger than approximately two gigabytes minus 64K. This limitation applies to both 32-bit and 64-bit applications. It would be great if you could allocate multi-gigabyte arrays in 64-bit applications, but unfortunately, this is not the case.
However, when your application is a 64-bit one (or runs on a 64-bit system when built with the Any CPU platform target), you can happily allocate multiple two gigabyte arrays without any problem, provided of course that there is enough system memory available.
Bear also in mind that the size limitation only applies to single objects. If you have an object that merely holds references (pointers) to other objects, like a list or a collection, you don't need to limit yourself to the roughly two gigabyte limit.






