Customizing the Microsoft .NET Framework Common Language Runtime
|
The hosting of the CLR within Microsoft SQL Server 2005 has required the CLR to take a new approach to obtaining the resources it historically has obtained directly from the operating system. Specifically, a new level of abstraction has been added to the Microsoft .NET Framework 2.0 CLR that enables a host to supply the CLR with resources such as memory, threads, and synchronization primitives. This abstraction layer is made available to hosts in the form of new managers in the CLR hosting API. If the CLR is hosted and the host has indicated the desire to supply the CLR with a specific type of resource by implementing the appropriate manager, the CLR will call the host to obtain the resource instead of getting it directly from the operating system. The CLR hosting API includes managers that enable the host to supply the CLR with the basic primitives it needs to allocate and free memory, create and destroy executable tasks, queue work items to a thread pool, create synchronization primitives, and so on. The CLR's new approach to obtaining the basic resources it needs to run programs is very powerful because it enables the CLR to be integrated into environments with very specific requirements for resource management. In this chapter, I discuss the APIs a host can use to supply the CLR with the primitive functions it needs to manage memory. In Chapter 14, I discuss how a host can use the CLR hosting API to integrate the CLR into environments with specific threading and concurrency requirements. To gain a better understanding of the scenarios in which a host might want to provide the hosting managers that enable it to replace the basic primitives the CLR uses to create and manage resources, consider SQL Server requirements. In many ways, SQL Server behaves like an operating system on machines on which it runs. For example, SQL Server closely manages all the memory it uses, it can be run in a mode in which it manually schedules executable tasks on fibers instead of leaving all scheduling up to the operating system, and so on. These custom subsystems are highly tuned to provide the highest overall throughput and performance in the most critical SQL Server scenarios. The primary challenge in integrating the CLR into SQL Server 2005 was getting two systems that were designed independently to cooperate on issues related to resource management in such a way that the overall solution doesn't adversely affect SQL Server scalability and performance requirements. Memory management provides a good example illustrating the changes required by the CLR to ensure a seamless integration with SQL Server 2005. SQL Server operates within a configurable amount of memory. In many cases, SQL Server is the only application running on a given server and is therefore configured to use most all of the machine's physical memory. A key design goal of SQL Server is never to allocate more memory than it is configured to use. Although it is certainly possible, given the operating system's virtual memory system, allocating more memory than is physically available causes memory pages to be swapped out to disk only to be reloaded later when they are needed. Paging in the virtual memory system introduces a performance cost that is unacceptable in many SQL Server scenarios. In other words, if the request to execute a particular query would cause the operating system to page, SQL Server is designed to fail the request rather than incur the performance cost associated with demand paging. SQL Server tracks all memory allocations made in the process to ensure it never exceeds the amount of memory it is configured to use. If a request to allocate memory would cause SQL to exceed its configured limit, that request is denied. This approach works great as long as SQL Server is the only entity in the process that is allocating memory. However, the introduction of the CLR into the process means that there is an additional entity making requests for memory. Clearly, for SQL Server to be able to track all memory allocated in the process accurately, all of the CLR's requests for memory must go through SQL Server instead of directly to the operating system. This is where the CLR hosting APIs come into play. By implementing a memory manager using the CLR hosting API, SQL Server can intercept all memory requests and handle them as it sees fit. In this way, SQL Server is able to track all memory requests in the process accurately regardless of whether they are initiated by SQL Server or by the CLR. In addition, if a memory request initiated by the CLR would cause SQL Server to exceed its configured limit, SQL Server can return a failure to the CLR indicating that no more memory is available. In this way, SQL Server can regulate the amount of memory the CLR can use. The redirection of the CLR's memory requests through the hosting API and into SQL Server is shown in Figure 13-1. Figure 13-1. The CLR redirects all requests for memory through the hosting API while running inside SQL Server.
The CLR hosting API exposes two managers that hosts can use to configure how the CLR uses memory in the process. The first of these managers enables a host to supply the CLR with basic memory allocation primitives, whereas the second hosting manager provides functions a host can use to configure the CLR's garbage collection. I cover both of these managers in detail throughout the chapter. |
|