Heap Management in Windows programming (too low-level, generally don't care)

Source: Internet
Author: User

Abstract: This paper mainly discusses the heap management technology in Windows Memory management, and briefly introduces the creation of heap, the allocation and redistribution of memory blocks, the revocation of heap, and the use of new and delete operators.

Keywords: heap; heap management
   1 Introduction

In most Windows application designs, it is almost inevitable that memory should be manipulated and managed. This is especially important in the dynamic allocation of large-size memory. This paper mainly discusses the heap management technology in memory management.

The heap is actually a region in the reserved virtual address space. At first, most of the pages in the reserved area were not submitted to physical memory. As more and more memory allocations are made from the heap, the heap manager will gradually commit more physical storage to the heap. The physical memory of the heap is allocated from the system page file and is released with a dedicated heap manager responsible for reclaiming the occupied physical memory. Heap management is also a memory management mechanism provided by Windows. Used primarily to allocate small chunks of data. Compared with the other two memory management mechanisms of Windows, the heap can focus on the design of program function code, rather than the cumbersome and easily overlooked issues such as the allocation granularity and page boundaries of the system. However, using heaps to allocate and free memory is much slower than the other two mechanisms and does not have the ability to directly control the submission and recycling of physical memory.

When the process was just started, a heap was created in the process virtual address space that was just created, which is the default heap for the process, and the default size is 1MB, which allows changes to be made when the program is linked. The default heap for a process is more important and can be used by many Windows functions. When used, the system must ensure that, for a specified period of time, only one thread can allocate and release blocks of memory in the default heap. While this restriction will have a certain impact on access speed, it can guarantee sequential access to the default heap when multiple threads in the process invoke various Windows functions at the same time. Multiple heaps are allowed in the process, and each heap, including the default heap, is identified by a heap handle in the process. Unlike the heap that you create, the process default heap is created and destroyed by the system, and its lifetime is already started before the process starts executing, although in the program you can get the default heap handle of the process through the GetProcessHeap () function. However, it is not allowed to invoke the HeapDestroy () function explicitly to undo it.

   2 Requirements for dynamic heap creation

As mentioned earlier, in the process, in addition to the process default heap, you can dynamically create some independent heaps in the process virtual address space. There are several aspects to consider when designing a program that requires no dynamic creation of a separate heap, from the need to protect components, to more efficient management of memory, the need for local access, the need to reduce thread synchronization overhead, and the need to quickly release heaps.

The principle of the need for protection of components is easier to understand. In Figure 1, the diagram on the left represents the case where a linked list (node structure) component and a tree (branch structure) component work together on a heap. In this case, due to the mixed storage of the two component data in the heap, if the last few bytes of Node 3 (which are part of the linked list component) are overwritten by the error, it will likely affect the branch 2 (which belongs to the tree component) that is located behind it. This causes the associated code of the tree component to traverse its tree as memory is destroyed. The reason for this is that the memory of the tree component is caused by the wrong operation of the linked list on its own. If the tree component and the linked list component are stored separately in a separate heap, as shown in the diagram on the right, it is not obvious that the error will be limited to the linked list component that did the wrong operation, and the tree component is protected by storing it in a separate heap.


Figure 1 The role of dynamically creating a heap in a protected component

In, if each node of the list component occupies 12 bytes, the branch of each tree component occupies 16 bytes If these lengths of objects share a heap (left), the objects in the left-hand image that have been allocated memory are already full of heaps, and if there are nodes 2 and 4 released, they will produce 24 bytes of fragmentation. If you attempt to allocate a 16-byte branch object within a 24-byte idle interval, the allocation will fail even though the number of bytes to allocate is less than the number of free bytes. It is only possible to allocate objects of the same size on the stack to implement more efficient memory management. If you replace a tree component with another 12-byte component, after releasing an object, the other object can be filled in exactly the object space that was just freed.

The need for local access is also a more important principle. The system often makes a page exchange between the memory and the system page file, but if there are too many exchanges, the performance of the system will be greatly affected. Therefore, in the design of the system should try to avoid frequent exchange of pages, if those will be accessed at the same time the data allocated in close proximity to each other, will reduce the system between the memory and page file Exchange frequency.

Thread synchronization overhead refers to the overhead that the heap runs sequentially under the default conditions to protect data from being destroyed when multiple threads try to access them concurrently, and that additional code must be executed. This overhead guarantees heap-to-thread security and is therefore necessary, but for a large number of heap allocation operations, this additional overhead becomes a burden and reduces the performance of the program. To avoid this additional overhead, you can notify the system that only a single thread is accessible when a new heap is created. At this point the heap security on the thread will have the application to be responsible.

Finally, if there is a need to quickly free up the heap, use the dedicated heap for some data structures and release the entire heap without explicitly releasing every chunk of memory allocated in the heap. For most applications, such processing will run at a faster speed.

3 Creating a heap

In the process, if you need to dynamically create a heap on the basis of the original default heap, it can be done by the HeapCreate () function:

HANDLE HeapCreate (
DWORD Floptions,
DWORD Dwinitialsize,
DWORD dwMaximumSize
);


Its first parameter, floptions, specifies the operation properties for the new heap. This flag will affect access to the new heap for some heap functions such as HeapAlloc (), HeapFree (), HeapReAlloc (), and HeapSize (). The possible values are the following flags and their combinations:

Property Flags Description
Heap_generate_exceptions When a function fails due to a memory out of bounds, an exception is thrown by the system to indicate this failure, rather than simply returning a null pointer.
Heap_no_serialize Indicates that the mutex does not appear


The parameters dwinitialsize and dwmaximumsize are the initial size of the heap and the maximum size of the stack, respectively. Where the value of Dwinitialsize determines the number of bytes originally committed to the heap. If you set a number that is not an integer multiple of the page size, it will be rounded to the adjacent page boundary. dwMaximumSize, in fact, is the maximum number of bytes of the address space area that the system can reserve for the heap. If the value is 0, an extensible heap is created, and the heap size is limited only by the available memory. If your application needs to allocate large chunks of memory, you typically set this parameter to 0. If dwMaximumSize is greater than 0, the value limits the maximum value that the heap can create, and heapcreate () also rounds the value to a neighboring page boundary, and then retains a chunk of that size for the heap in the virtual address space of the process. The memory block size allocated in this heap cannot exceed 0x7fff8 bytes, and any attempt to allocate a larger block of memory will fail, even if the heap size is set to accommodate the block of memory. If HeapCreate () executes successfully, it will return a handle that identifies the new heap and is available to other heap functions.

In particular, when setting the first parameter, it is prudent to use the flag of heap_no_serialize, which should generally be avoided. This is related to the execution of the heap function HeapAlloc () that will be performed later, and when HeapAlloc () attempts to allocate a block of memory from the heap, the following steps are performed:

1) A linked table that iterates through the allocated and freed blocks of memory

2) search for the address of a free memory block

3) Allocate a new block of memory by marking the free memory block as "allocated"

4) Add the newly allocated memory block to the memory block list

If there are two threads 1, 2 attempting to allocate memory blocks from a heap at the same time, thread 1 will get the address of the space memory block after performing the above 1 and 2 steps. However, due to the CPU on the thread run time Shard, so that thread 1 before performing the 3rd step, it is possible for thread 2 to take execution and have the opportunity to perform the same 1, 2 steps, and because the first execution of the thread 1 does not carry out to 3rd step, so thread 2 will find the address of the same free memory block, and mark it as assigned. Thread 1, after resuming running, does not know that the memory block has been tagged by thread 2, so there will be two lines Cheng June think it allocates an idle block of memory and update their respective join tables. Obviously, errors like these two threads having exactly the same memory block address are very serious and difficult to spot.

Because this problem is only possible when multiple threads are operating concurrently, a simple workaround is to allow only a single thread to have exclusive access to the heap and its joined tables without using the HEAP_NO_SERIALIZE flag. If you must use this flag, for security reasons, you must ensure that the process is single-threaded, or that multiple threads are used in the process, but only a single thread accesses the heap. Then there are multi-threading, multiple threads accessing the heap, but these threads are using some kind of thread synchronization method. If you can make sure that one of the above is true, you can safely use the HEAP_NO_SERIALIZE flag, and you will have fast access speed. If you are not sure whether the above conditions are met, it is recommended that you do not use this flag to access the heap sequentially, although the thread speed may decrease but it will ensure that the heap and the data in it are not destroyed.

   4 allocating memory blocks from the heap

After a heap has been successfully created, you can call the HeapAlloc () function to allocate memory blocks from the heap. Here, in addition to allocating memory blocks from the dynamic heap created with heapcreate (), you can also allocate memory blocks directly from the default heap of the process. The following first gives the function prototype of HeapCreate ():

LPVOID HeapAlloc (
HANDLE Hheap,
DWORD DwFlags,
DWORD dwbytes
);


Where the parameter hheap is the handle to the heap from which the memory block is to be allocated, either a dynamic heap handle created from heapcreate () or a default heap handle that is obtained by GetProcessHeap (). The parameter dwflags specifies the individual flags that affect heap allocation. The flag overrides the corresponding flag specified when calling HeapCreate (), and the possible values are:

Sign Description
Heap_generate_exceptions This flag specifies that an exception will be thrown instead of simply returning a null pointer in cases such as a memory out-of-bounds operation.
Heap_no_serialize Forcing a call to HeapAlloc () will not be in sequence with other threads that access the same heap
Heap_zero_memory If this flag is used, the contents of the newly allocated memory will be initialized to 0

The last parameter of


, dwbytes, sets the size of the block of memory to allocate from the heap. If HeapAlloc () executes successfully, the address of the memory block allocated from the heap will be returned. If the execution of the HeapAlloc () function fails due to insufficient memory or some other reason, an exception will be thrown. The exception flag can be used to cause the memory allocation failure: If the status_no_memory is caused by insufficient memory, if it is Status_access_ Violation indicates that an attempt to allocate a memory block has failed because the heap is corrupted or the function parameter is incorrect. The above exception occurs only if the HEAP_GENERATE_EXCEPTIONS flag is specified, and if this flag is not specified, the HeapAlloc () function simply returns a null pointer if a similar error occurs.

When setting the dwflags parameter, if the HEAP_GENERATE_EXCEPTIONS flag was previously specified when the heap was created with heapcreate (), it is no longer necessary to set the Heap_generate_exceptions flag. Because the HEAP_GENERATE_EXCEPTIONS flag has notified the heap that an exception will be thrown when a block of memory cannot be allocated. In addition, the HEAP_NO_SERIALIZE flag should be set cautiously, similar to the use of the HEAP_NO_SERIALIZE flag in the HeapCreate () function, which would be destroyed if other threads were using the same heap at the same time. This flag is absolutely disabled if the memory block is allocated in the process's default heap. The

uses the heap function HeapAlloc () to note that the use of heap in memory management is primarily used to allocate smaller chunks of data, and if the amount of memory to allocate is around 1MB, then the heap is not used to manage memory, but the memory management mechanism of virtual memory should be chosen.

5 reallocate memory block

in the program design often due to the initial lack of foreseen in the heap allocated memory block size is inappropriate (in most cases, the initial allocation of memory is small, And then it actually needs more data to be copied into the memory block. This requires that the memory block is allocated and then resized as needed. The heap function HeapReAlloc () will complete this function, with the function prototype:

lpvoid HeapReAlloc (
HANDLE hheap, 
DWORD dwFlags,
LPVoid lpmem, 
DWORD dwbytes 
);


Where the parameter hheap is a handle to the heap that contains the block of memory to be resized. The dwflags parameter specifies the flags used by the HeapReAlloc () function when changing the memory block size. The possible values are Heap_generate_exceptions, Heap_no_serialize, Heap_realloc_in_place_only, and Heap_zero_memory, The first two flags have the same effect as in HeapAlloc (). The HEAP_REALLOC_IN_PLACE_ONLY flag does not move the memory block in the heap when the memory block is enlarged, and if the memory is incremented without setting this flag, then the HeapReAlloc () function will likely move the original memory block to a new address. Obviously, when the flag is set to prevent memory from being adjusted, it is possible that there is not enough memory to attempt to increase the amount of memory used, in which case the function is failing to resize the memory block, and the memory block will still retain its original size and position. The use of the HEAP_ZERO_MEMORY flag is slightly different, if the memory is quickly adjusted larger than before, then the newly added portion of memory will be initialized to 0, if the adjusted memory block is reduced, then the flag will not play any role. The last two parameters of the

function, Lpmem and dwbytes, are pointers to the re-allocated memory block and the number of bytes that were redistributed. If the function executes successfully, the new address of the memory block that changed the size is returned. If the HEAP_REALLOC_IN_PLACE_ONLY flag is used at the time of invocation, the address returned will be the same as the original memory block address. If the execution of a function fails because of insufficient memory, the function returns a null pointer. However, the execution failure of HeapReAlloc () does not affect the original memory block, it will keep the original size and position continue to exist. The actual size of the memory block can be retrieved through the HeapSize () function.

6 free heap memory, undo heap

When you no longer need to use a block of memory in the heap, you can release it by HeapFree (). The function structure is simple and contains only three parameters:

BOOL heapfree ( br> HANDLE hheap,
DWORD dwflags, 
lpvoid lpmem
);


where Hheap is the handle to the heap to which the memory block is to be freed, the release option for the parameter dwflags to the stack can be either 0 or heap_no_serialize, and the last parameter Lpmem as a pointer to the memory block. If the function executes successfully, the specified memory block is freed, and true is returned. The main purpose of this function is to help the heap manager to reclaim some unused physical storage to free up more free space, but it is not guaranteed to succeed.

Finally, you can call the Heapdestory () function to destroy a program before it exits or if the application no longer needs the heap it created. The function contains only one parameter-the handle to the heap to be destroyed. Successful execution of the Heapdestory () will release all memory blocks contained in the heap, and return all the physical storage and reserved address space areas that the heap occupies to the system and return true. The function only acts on a heap that is explicitly created by HeapCreate () and cannot destroy the default heap of the process, and if a handle to the default heap obtained by GetProcessHeap () is forced to call Heapdestory () as a parameter, the call to the function is ignored.


7 overloading of new and delete operators

New and delete memory space dynamic allocation operators are a common way of using heaps for memory management in C + +. The heap objects can be created or deleted by these two operators at any time as needed during the program's operation. The new operator allocates a large enough chunk of memory in the heap to hold the object of the specified type, and if the object type is constructed differently each time, it needs to be allocated according to the space occupied by the largest object. After successful execution, the new operator returns a pointer to the type that matches the object assigned to new, and if it does not match it is forced to cast the type, otherwise it will compile an error. When this object is no longer needed, you must explicitly call the delete operator to free the space. This is important if you do not explicitly call the delete operator before you construct another object in the pre-allocated buffer or before releasing the buffer, then the program will have unpredictable consequences. When using the delete operator, you should be aware of the following:  

1) It must be used for the pointer returned by operator new

2) The operator also applies to the null pointer

3) The pointer name is only used with a square bracket character, And regardless of the number of dimensions of the deleted array, ignore any number in square brackets

Class cvmshow{
Private
Static HANDLE m_sheap;
static int m_sallocedinheap;
Public
LPVOID operator new (size_t size);
void operator Delete (lpvoid pVoid);
}

......
HANDLE m_sheap = NULL;
int m_sallocedinheap = 0;
LPVOID cvmshow::operator New (size_t size)
{
if (m_sheap = = NULL)
M_sheap = heapcreate (heap_generate_exceptions, 0, 0);
LPVOID pVoid = HeapAlloc (m_sheap, 0, size);
if (pVoid = = NULL)
return NULL;
m_sallocedinheap++;
return pVoid;
}
void Cvmshow::operator Delete (lpvoid pVoid)
{
if (HeapFree (m_sheap, 0, pVoid))
m_sallocedinheap--;
if (M_sallocedinheap = = 0)
{
if (Heapdestory (M_SHEAP))
M_sheap = NULL;
}
}


In addition to using new and delete directly in the program to create and remove heap objects, you can easily leverage the stack function by overloading the C + + class with the new and delete operators. The above code simply overloads them and passes the static variables m_sheap and m_ Sallocedinheap shares a unique heap handle between all instances of the class cvmshow (because all instances of the Cvmshow class here are memory-allocated in the same heap) and the count of allocated class objects. These two static variables are initialized to a null pointer and a 0 count, respectively, when the code starts executing.

When the overloaded new operator is called for the first time, because the static variable m_sheap is NULL to indicate that the heap has not yet been created, a heap is created by the HeapCreate () function and the heap handle is returned to M_sheap. Memory is then allocated in the heap based on the size specified by the ingress parameter size, and the memory block counter m_sallocedinheap is allocated. In the subsequent invocation of the operator, because the heap has been created, the heap is no longer created, but instead is allocated a specified size of memory block directly in the heap and counts the number of allocated memory blocks.

When the Cvmshow class object is no longer being used by the application, it needs to be undone and done by the overloaded delete operator. The delete operator accepts only one LPVOID parameter, which is the address of the deleted object. The function, when executed, first calls the HeapFree () function to release the specified allocated memory object and decrements the allocated memory count by 1. If the count is not zero, the memory block in the current heap is not fully released, and the heap is temporarily not undone. If the m_sallocedinheap count is reduced to 0, all Cvmshow objects have been disposed of in the heap, and you can call the Heapdestory () function to destroy the heap and set the heap handle m_sheap to a null pointer. The operation of setting the heap handle to a null pointer after undoing the heap is absolutely necessary. If you do not do this, when the program calls the new operator again to allocate a Cvmshow class object, it will assume that the heap is present and will attempt to allocate memory in the undone heap, which will obviously result in a failure.

Classes designed like Cvmshow are overloaded with the new and delete operators and are allocated in a heap for all Cvmshow class objects, saving the allocation overhead and memory of creating heaps for each class. Such processing can also allow each class to have its own heap and allow derived classes to share it, which is also a good way to handle programming.

   8 Summary

The use of the heap can sometimes cause the system to slow down, usually due to the slow speed of the allocation operation, the slow speed of the release operation, the slow rate of heap contention, the slow rate of heap destruction, the slow rate of frequent allocation and redistribution, and so on. Among them, competition is the problem of slowing down in allocation and release operations. For these reasons, it is recommended that you do not use heaps too frequently in your programs. The code described in this article is compiled by Microsoft Visual C + + 6.0 under Windows Professional.

Http://www.cnblogs.com/qiubole/archive/2008/03/07/1094695.html

Heap Management in Windows programming (too low-level, generally don't care)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.