There is always a newly-introduced Windows programmer asking me what the Windows handle is, and I say you see it as a pointer-like identifier, but obviously the answer doesn't make them happy, and then I say go ask the Niang, they say not too much on the internet is difficult to understand. Today more busy, I surf the internet to check, just Baidu encyclopedia entry "handle" There are several kinds of statements, a lot of narrative is wrong, God knows what these fraught people want to do.
Here I list the entry of the description of the handle of the improper, as to how to ignore the first, continue to look down will understand:
1.windows to set up a handle, fundamentally rooted in the memory management mechanism of the problem-virtual address, in short, the data address needs to change, after the change needs someone to record management changes, (as if the hukou management), so the system with a handle to record data address changes.
2. If you want to know the handle more thoroughly, I can tell you that the handle is a pointer to the pointer.
Usually we say that a handle is a unique integer that Windows uses to identify objects that are created or used by the application. This sentence is not a problem, but want to match this sentence to the specific memory structure can not be done. Let's explore in detail what the handles in Windows are.
1. Virtual Memory structure
To understand this problem, you cannot avoid the virtual memory structure of Windows first. For this problem has been written a better explanation, here I to ensure that the blog coherence, directly paste the necessary parts (the original is to explain the Java JVM Virtual machine Performance improvement of the article, in which involved in the virtual memory content, explained very good, here I intercept this part slightly modified, here is the article link)
We know that the CPU accesses memory by addressing it. The addressing width of the 32-bit CPU is 0~0XFFFFFFFF, and the computed size is 4G, which means that the maximum supported physical memory is 4G. However, in the course of practice, encountered such a problem, the program needs to use 4G of memory, and the available physical memory is less than 4G, causing the program to reduce memory consumption.
In order to solve such problems, modern CPUs introduced the MMU (Memory Management unit RAM Management Unit).
The core idea of the MMU is to replace the physical address with the virtual address, that is, when the CPU is addressing, and the MMU is responsible for mapping the virtual address to physical addresses. The introduction of the MMU solves the limitation of physical memory, which is the same as using 4G memory for the program.
Memory Paging (Paging) is a memory management mechanism proposed on the basis of the use of MMU. It splits the virtual address and physical address by a fixed size (4K) into pages and page frames (page frame) and guarantees that the page is the same size as the page frame. This mechanism, from the data structure, guarantees efficient access to memory and enables the OS to support non-contiguous memory allocations. When the program memory is not enough, you can also transfer the infrequently used physical memory pages to other storage devices, such as disk, which is familiar with the virtual memory.
As mentioned above, the virtual address and physical address need to be mapped to make the CPU work properly.
Mapping requires the mapping table to be stored. In modern CPU architectures, mapping relationships are typically stored in physical memory where a page table is called.
Such as:
From this diagram, you can clearly see the interaction between the CPU and the page table, the physical memory.
Further optimization, introduction of TLB (translation lookaside buffer, page table register buffer)
As we know from the previous section, the page table is stored in memory. We know that the CPU accesses the memory through the bus, certainly slower than the direct access register.
To further optimize performance, the Modern CPU architecture introduces the TLB to cache part of the frequently accessed page table content.
Such as:
In contrast to 9.6, the TLB is added in the middle.
Why should I support large memory paging?
The TLB is limited, no doubt about it. TLB miss occurs when the TLB's storage limit is exceeded, and then the OS commands the CPU to access the page table in memory. If the TLB miss is frequent, the performance of the program will drop quickly.
In order for the TLB to store more page address mappings, our approach is to increase the paging size of the memory.
If a page 4M, compared to a page 4K, the former can allow the TLB to store more than 1000 page address mapping relationship, performance improvement is relatively considerable.
In short, virtual memory to the memory logical address and physical address to establish a corresponding table, to read and write the logical address corresponding to the physical memory content, you must query the relevant page table (of course, there are still segments, page-style memory correspondence, but the principle is the same) to find the logical address corresponding to the physical address to do related operations. Our common memory allocation interface for programmers, such as malloc, is assigned a logical address, and the C pointer points to a logical address.
The benefits of this virtual memory are many, as an example of continuous memory allocation and removable memory.
First of all, we often need to allocate a contiguous memory structure in our programs, such as arrays, which they can iterate through using pointers, but the physical memory is actually broken after multiple allocations are released, as
The white is available physical memory, black for the memory that is occupied by other programs, now to allocate a 12 size of contiguous memory, then obviously the physical memory is not so large contiguous memory, this time through the page table corresponding to see we can easily get logical address on the contiguous 12 size of memory.
Say again the removable memory, we use GlobalAlloc and other functions, often specify the gmem_movable and gmem_fixed parameters, very people on these two parameters very headache, do not understand what meaning.
In fact, the movable and fixed are all for the logical address. Gmem_movable is said to allow the operating system (or application) to implement the management of the memory heap (logical address), if necessary, the operating system can move the memory block to obtain a larger block, or merge some free memory blocks, also known as "garbage collection", it can improve the utilization of memory, The address here refers to the logical address. Similarly to allocate 12 size contiguous memory, in a certain state, the memory structure is as follows
Obviously this time is unable to allocate 12 contiguous size of memory, but if the logical address here is indicated as gmem_movable, the operating system this time will be the logical address management, get the following results
At this time, the implementation of the logical address of the move, relative to the physical memory of the movement, the cost of course is much smaller, but the smart small partners are not to ask, so in the logical address of the memory, then the actual access data is not chaos, but also to find their own allocation of actual physical memory data, and so on, Don't be impatient, this is what you have to say about the handle.
Gmem_fixed is said to allow the movement of memory blocks in physical memory, but must ensure that the logical address is unchanged, in the earlier 16-bit Windows operating system does not support moving memory in physical memory, so prohibit the use of gmem_fixed, now you do not realize the estimate.
In fact, when allocating memory with GlobalAlloc, the handle returned by the specified gmem_fixed parameter is a pointer to memory allocated memory block, do not understand??? Then look at the structure of the handle below, and you'll see.
2. The handle structure in the process of explaining the virtual memory structure above, we have raised several questions: why the memory access of movable is not chaotic, why the fixed memory is pointing to the allocation of memory blocks of pointers. In fact we don't have the source code for Windows, but we can get a glimpse of some header files, MSDN, and early memory allocation functions in Windows. A generic handle definition was made in the Winnt.h header file
[CPP]View PlainCopyprint?
- #ifdef STRICT
- typedef void *HANDLE;
- #define DECLARE_HANDLE (name) struct name# #__ {int unused;}; typedef struct name# #__ *name
- #else
- typedef PVOID HANDLE;
- #define DECLARE_HANDLE (name) typedef HANDLE Name
- #endif
- typedef HANDLE *phandle;
The definition of a special handle was made in Windef.h
[CPP]View PlainCopyprint?
- #if!defined (_MAC) | | !defined (gdi_internal)
- Declare_handle (hfont);
- #endif
- Declare_handle (hicon);
- #if!defined (_MAC) | | !defined (win_internal)
- Declare_handle (HMENU);
- #endif
- Declare_handle (hmetafile);
- Declare_handle (hinstance);
- typedef HINSTANCE hmodule; / * Hmodules can used in place of hinstances */
- #if!defined (_MAC) | | !defined (gdi_internal)
- Declare_handle (Hpalette);
- Declare_handle (hpen);
- #endif
- Declare_handle (HRGN);
- Declare_handle (hrsrc);
- Declare_handle (HSTR);
- Declare_handle (htask);
- Declare_handle (hwinsta);
- Declare_handle (HKL);
Here Microsoft defines the universal handle handle as a void pointer, obviously, he does not want to let people know the real type of handle, but as he has done before, Microsoft has a good idea that the result is not realized. Immediately, if the mandatory type check strict is defined, he also defines a special type of handle macro Declare_handle, where the use of # #, this is a relatively remote usage, translated, for example, Declare_handle (HMENU) definition is actually
[CPP]View PlainCopyprint?
- typedef struct HMENU__
- {
- int unused;
- } *HMENU;
Here, do you feel a little bit of a point, right,A handle
is a pointer to a struct body, combined with the int unused definition here, it is easy to guess that the first field of a struct is our logical address (pointer). Well, is not just so, of course not!!! Since pointing to the struct pointer can force truncation to get only the first field, there is definitely more than one field in the struct struct, and we have to contact our programming experience in Windows, so there must be a count segment for thread handle. For kernel objects such as event Hevent, a property segment must be required, so there must be a removable and non-removable handle for memory allocation, and so on. Based on this we can boldly guess that the structure of Windows is pointing to something like the following
[CPP]View PlainCopy print?
- STRUCT    
- {
- int pointer; //pointer segment
- int count; //kernel count segment
- int attribute; // File attribute segment: Shared and so on
- int Memattribute; //memory attribute segment: movable and fixed, etc.
-     ...  
- };
In fact, the Windows Memory Manager is actually managed by the handle, through the handle to manage the pointer, the Windows system organizes memory when the memory attribute segment is detected, if it can be moved to move the logical address, after the move, the new address is updated to the corresponding handle of the pointer segment, When you want to use the movable address must lock, this time the Count plus 1, the memory Manager detects the Count >0 will not move the logical address, this time to obtain a fixed logical address to operate physical memory, after the use of unlock memory manager can move the logical address, To this movable memory access why not disorderly this problem is solved. Again, why is a fixed memory a pointer to a memory block? Looking at the generic handle definition above, we can find that the handle definition of handle is always a void pointer, and the other special handles are defined as struct pointers when strict type checking, why not define them as the same. View MSDN's narrative about GlobalAlloc for the gmem_fixed type "allocates fixed memory. The return value is a pointer. ", here is a pointer, in order to verify this statement, I wrote a short program
[CPP]View PlainCopyprint?
- Gmem_fixed
- Hglobal = GlobalAlloc (gmem_fixed, (Lstrlen (szbuffer) +1) * sizeof (TCHAR));
- Pglobal = GlobalLock (hglobal);
- lstrcpy (Pglobal, szbuffer);
- _tprintf (TEXT ("Pglobal and hglobal%s\n"), Pglobal==hglobal? Text ("equal"): Text ("unequal"));
- GlobalUnlock (HGLOBAL);
- _tprintf ("data accessed using a handle as a pointer is:%s\n"), hglobal);
- GlobalFree (HGLOBAL);
Run the result as
[Plain]View PlainCopyprint?
- Pglobal and Hglobal are equal
- The data accessed using a handle as a pointer is: Test text
Compare the use of the Gmem_movable program to
[CPP]View PlainCopyprint?
- Gmem_movable
- Hglobal = GlobalAlloc (Gmem_moveable, (Lstrlen (szbuffer) +1) * sizeof (TCHAR));
- Pglobal = GlobalLock (hglobal);
- lstrcpy (Pglobal, szbuffer);
- _tprintf (TEXT ("Pglobal and hglobal%s\n"), Pglobal==hglobal? Text ("equal"): Text ("unequal"));
- _tprintf ("data accessed using a handle as a pointer is:%s\n"), hglobal);
- GlobalUnlock (HGLOBAL);
- GlobalFree (HGLOBAL);
Run the result as
[CPP]View PlainCopyprint?
- Pglobal and hglobal are not equal
- The data accessed using a handle as a pointer is:?
Obviously, the data types obtained using gmem_fixed and gmem_movable are not the same, and we have reason to believe that Windows is returning data pointers when calling GlobalAlloc to use gem_fixed. Using Windows to return a handle to the struct when calling gmem_movable, the reason for the operation is believed to be more convenient to use. So here we are going to revise the previous statement:The
general handle handle is sometimes a logical pointer, and most of the time it is a struct pointer, and a special handle such as Hmenu is a struct pointer. So the second problem is solved.
So in summary, it is the following picture below, we look back at the beginning of the blog to say the improper, saying that they are improper because it is not a complete error: 1th, it is true that the handle has management memory address changes, but not only this role, the kernel object access level, the file is open is related to him 2nd, pointers to pointers can be seen by the author as well, but he ignores the other functions that the handle contains and the role of managing memory addresses. So here's the handle you should understand very well, on this basis we can have some inspiration in Windows programming: 1.
common handle handle and special handles can be converted to each other in general, but sometimes they go wrong.2. If you do not consider cross-platform porting, you should use more memory management functions provided by the Windows SDK, so that you can get better memory management 3. The implementation of the C language memory allocation function relies on the use of gmem_fixed to invoke the memory allocation function of the Windows SDK.
Full test source code Download link Note Some of the content described in this article may not be seen in the new VS2005 series compilers, because some of the code is not so perfect at VC6 time, so it gives us the opportunity to tap into potential content. As for Microsoft's painstaking consideration not to let us see the true definition of the handle is inevitable, imagine that the main memory object structure has been touched, then the hackers are not anti-day. Original, reprint please indicate from http://blog.csdn.net/wenzhou1219
http://blog.csdn.net/wenzhou1219/article/details/17659485
Learn more about what a Windows handle is (a handle is a logical pointer, or a pointer to a struct, illustrated, and very clear) good