A Brief Introduction to Managed Applications

As mentioned previously, managed applications are compiled to an intermediate byte code called the Common Intermediate Language. This language is simply a series of byte codes that define an opcode set for a virtual stack-based processor. A run-time engine, implemented in native CPU instructions, converts the byte codes to native instructions and then has the CPU execute the native instructions. This process, called just-in-time compilation, differs from conventional interpreters because the native instructions are cached. If the method is executed again, the cached native instructions are directly called instead of the original byte codes being reinterpreted as in an interpreter. One can argue the merits of waiting to convert virtual instructions to native instructions at run time; this text simply accepts that the .NET runtime uses this process.

Performance of a JIT runtime, while inferior to that of native compiled code, isn't as bad as you might think. The compilation takes place only on the code paths being executed in the module, so any code not executed isn't compiled. Also, because most routines execute many times, the average speed of a routine will eventually approach the speed of precompiled native code. As long as the system retains enough free memory, the cache will retain the code for the application, alleviating the need to recompile the methods.

In low-memory conditions, the execution engine tries to recover memory in a process called garbage collection. During garbage collection, the runtime finds all the discarded heap objects and recovers that memory for reuse. The remaining objects that are still in use are relocated to the start of the heap. Because this process involves moving in-use objects, all threads in the application are suspended during the garbage collection. If the garbage collection doesn't free enough memory, parts of the code cache can be purged in a process called code pitching. If code for a method is pitched and that method is executed again, the original byte codes are reloaded and recompiled.

Microsoft currently supports two high-level languages for generating CIL byte codes for execution on the Compact Framework runtime: Visual Basic .NET and Visual C#. Both tools come with components to generate Compact Framework applications and automatically deploy the application to devices or emulators. Visual Studio also has a remote debugger that debugs the code on the device remotely from a connected PC. Microsoft doesn't provide a tool for generating managed code for the Compact Framework with its C++ compiler.

While many embedded developers are familiar with Visual Basic, if only to sneer at Visual Basic developers, C# (pronounced C sharp) is a new language created by the developers at Microsoft to be a better C++. C# retains most of C++'s syntax while providing improvements that tend to encourage safer code.

Regardless of opinions and snobbery of some developers, the runtime doesn't care about the high-level language used to create a Compact Framework application as long as the compiler produces the IL byte codes supported by the runtime. One of the nicer features of the .NET environment is that the full power of the runtime and its accompanying class library is available to all languages equally. As a result, Visual Basic .NET programmers can now create applications just as powerful, fast, and functional as can be created with Visual C#.

This topic is from Programming Microsoft Windows CE, Third Edition, by Douglas Boling, published by Microsoft Press. © 2003 by Douglas McConnaughey Boling. Reprinted here by permission of the author.