In. NET programming, thanks to an effective memory management mechanism, object creation and use is more convenient, in most cases we do not have to care about object creation and allocation of memory details, you can rest assured that the object cleanup to automatic garbage collection to complete. Because. NET class library encapsulates the underlying objects of the system, and we do not need to invoke the Windows API to manipulate unmanaged objects. But not directly manipulating unmanaged objects does not mean that the program does not indirectly create these objects if you do not understand them. NET objects and unmanaged resources, we are likely to expose unmanaged resources due to inappropriate use of these managed objects. This article attempts to illustrate the basic concepts of Windows objects and handles, as well. NET programming, and to discuss the topic of handle leaks with some simple sample programs.
One, what is a handle?
In Windows programming, programs require access to a wide variety of resources, such as files, networks, Windows, icons, and threads. Different types of resources are encapsulated into different data structures, and when these resources need to be used, the program needs to create different objects based on these data structures, which should be released in a timely manner when the objects are finished and no longer needed. In Windows, applications cannot manipulate these objects directly in memory, but instead create, access, trace, and destroy these objects through a series of exposed Windows APIs that are created, accessed, tracked, and destroyed by the object manager. When these APIs are called to create objects, they do not directly return a pointer to the object, but instead return a 32-bit or 64-bit integer value, which is the handle (Handle), which is the only integer value in the process or system scope. The program then accesses the object again, or deletes the object, manipulating the handle indirectly as a parameter to the Windows API. In this process, the handle is used as the identity of the object in the system.
The object manager is a system-supplied system component for unified management of all Windows internal objects. The internal objects described here are different from the concepts of "objects" in high-level programming languages such as C #, but objects that are implemented and used by the Windows kernel or by individual components. These objects and their structures are either not exposed to user code, or they can only be manipulated by the encapsulated Windows API using a handle. In C # programming, in most cases, we don't need to deal with these Windows APIs because. NET class library to encapsulate these APIs, but our managed programs still indirectly create many Windows internal objects and hold their handles.
As mentioned above, the handle is a 32-bit or 64-bit integer value (depending on the operating system), so in a 32-bit system, C # can fully represent a handle with int. But. NET provides a struct system.intptr that is designed to represent a handle or pointer, and you should use the IntPtr type when you need to represent a handle, or if you want to use pointers in unsafe code.
Second, C # the procedure for creating a file handle in
For example, a file belongs to an unmanaged system resource. In C #, you can use the static method of the file class open to get a FileStream object that reads and writes the disk file. The FileStream object itself is a managed object, how does it relate to the unmanaged resource of the file?
In general, the operation of opening a file in C # follows these steps:
- Call. Net static method System.IO.File.Open, the file class creates a FileStream object and passes in the necessary parameters, such as file path, FileMode, and FileAccess options. The FileMode enumeration indicates that you want to create a new file, open an existing file, overwrite the original file, or append new content to the original file; The FileAccess enumeration indicates that you want to read the file, write the file, or both.
- Then FileStream calls its own Init method for initialization, and in this process there is more detail to consider. In order to create a file, the initialization method requires additional information and checks, such as whether the process allows other processes to read and write files when using the file, whether the file path is valid, whether there is sufficient permissions, whether the target file is a file type that is allowed to be accessed, Whether the combination of the FileMode and FileAccess options is set correctly.
- After completing these necessary checks, Filestream.init calls the Win32native.safecreatefile method.
- The Win32native class encloses a large number of Windows Api,safecreatefile methods to invoke the CreateFile API in Kernel32.dll P/invoke Way and return Safefilehandle. Safefilehandle is an interesting type that inherits from SafeHandle, which contains a file handle of the true IntPtr type: NET designer intentionally makes this handle field invisible, but if you want to get this handle value, Safefilehandle also provides the DangerousGetHandle () method to meet your requirements: All told you dangerous, you see.
- The safefilehandle containing the file handle is returned and stored in the FileStream object. Subsequent read and write operations, FileStream will use this handle to interact with the Windows API until the handle is finally closed. From the beginning to the end, our code does not need to be directly concerned with the existence of the handle, FileStream is responsible for most of the work.
III. benefits of manipulating objects through a handle
Windows does not allow applications to directly access the lower-level objects in memory, but is managed uniformly by the object manager, with the following benefits in general:
- At the operating system level, it provides a unified interface and mechanism for all programs to use system resources. Without the object manager, different programs will have a variety of implementations to access resources, and the code is scattered in various, difficult to standardize, and can not coordinate the resolution of resource contention.
- Isolate objects that need to be protected at the system level to provide greater security.
- All access to system-critical resources through the object manager, so that the system can easily track and limit the use of resources, access control.
Iv. viewing the number of handles for a process
So far, this article is all about the invisible concept, it is necessary to visually look at the use of the handle in the system. There are several ways to view the handle usage of a process, starting with both tools, Windows Task Manager, and process Explorer.
Task Manager does not display the number of handles by default, and the number of handles currently open in the process needs to be checked in the view-select column to see the number of handles. As shown, you can see that the Notepad process currently has 59 handles open.
The task Manager that comes with the system has a handy view of the number of handles, but if you want to know what these handles are, you can use process Explorer. Process Explorer is a session viewer in the Windows Sysinternals Toolkit, which can be downloaded from here. If you see a different view, you can click View, check Show Lower Pane, and select handles in Lower Pane view. After you select a process in the list, a detailed list of the handles in that process is displayed in the lower panel.
V. Why focus on the number of handles
The handle points to system resources such as windows, threads, files, menus, processes, and timers, and, like all things called "resources," scarcity is their common feature. For computers and operating systems, memory is a scarce resource, and all handles and objects are stored in memory. Based on this fact, the operating system does not allow the process to create objects and handles without restrictions. For the number of handles in the Task manager, the number of handles allowed to open per process is theoretically up to 2^24, but the actual number is greatly compromised due to memory limitations. In my test, 32-bit. NET process "handle number" after reaching more than 15 million, the program began to appear a variety of problems. In fact, the vast majority of programs do not use so many handles, unless special needs, in software programming, if your own program "handle number" of thousands or even thousands of, you need to pay special attention, which generally means that there is already a handle leak in the program.
You may have noticed that in the Task manager earlier in this article, in addition to displaying the handle number of the process, the number of user objects and GDI objects is displayed, and they belong to the other two handles. The specific differences we will introduce later, now we need to be clear that the system for both of these objects also set a quantitative limit. For "User objects" and "GDI objects", the maximum number of allowed creation per process is set in the registry, respectively, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Nt\currentversion\ Userprocesshandlequota and Gdiprocesshandlequota items in Windows, two items are set to 10000by default on 32-bit operating systems in Windows 7. You can change this setting, user objects can only be set to 18000 , GDI objects up to 65536 . However, changing this setting is not recommended, typically when your application needs more than 10,000 user objects or GDI objects, you should first check where the handle leaks, not the upper limit, Changing the upper limit does not mean that the application can really create and use so many object handles, and the actual available quantity is subject to the current system's available memory.
. NET object vs. Windows handle (a): The basic concept of a handle