zoukankan      html  css  js  c++  java
  • 第十八章 堆

    //1.
    (A):堆非常适合分配大量的小型数据。堆的优点是能让我们不必理会分配粒度和页面边界之类的事情,其缺点是速度较慢且无法进行精细控制
    (B):在系统内部,堆就是一块预定的地址空间地址,刚开始,区域内大部分页面没有调拨物理存储器,随着不断从堆中分配内存,堆管理器会调拨越来越多的物理存储器。
    释放堆中的内存块时,堆管理器会撤销已调拨的物理存储器
    (C):进程初始化的时候,系统会在进程地址空间创建一个堆,这个堆被称为进程的默认堆。其默认大小为1MB,使用链接器开关 /HEAP 可以改变默认大小
    (D):许多 Windows 函数需要用到进程的默认堆,比如API中 ANSI 字符串 转换为 UNICODE 字符串 时
    (E):一般对堆的访问都是依次进行的
    (F):默认堆是在进程开始运行之前由系统自动创建,在进程终止后自动销毁。 GetProcessHeap() 可以得到进程默认堆的句柄
    HANDLE WINAPI GetProcessHeap(void);
    Retrieves a handle to the default heap of the calling process. This handle can then be used in subsequent calls to the heap functions.
    (G):一般需要大于1MB的内存,建议使用 VirtualAlloc
    
    //2.
    自定义堆的好处:
    (A):对组件进行保护:不同组件创建自己的堆,防止某个组件存在bug,从而影响到其他组件,有利于bug查找
    (B):更有效的内存管理:防止不同组件因为不同大小,而在使用堆的过程中产生内存碎片
    (C):使内存访问局部化:当系统必须把一个内存页面换出到页交换文件,或把页交换文件的一个页面换入到内存,会对性能产生影响。若将内存访问局限在一个较小的地址空间中,
    则可以降低内存与磁盘之间进行交换的可能
    (D):避免线程同步的开销:默认情况下,对堆的访问是依次进行的,所以堆函数必须执行额外的代码来保证堆的线程安全性。如果创建一个堆,能确保只有一个线程访问他,
    则我们可以由自己来保证堆的线程安全性,来获得性能的提升
    (E):快速释放:把一些数据结构存入一个专门的堆中,则我们可以直接释放整个堆,而不必显示的释放堆中的每个内存块,则可提升性能
    
    //3.
    (A):
    HANDLE WINAPI HeapCreate
    (
    	__in DWORD flOptions,
    	__in SIZE_T dwInitialSize,
    	__in SIZE_T dwMaximumSize
    );
    Creates a private heap object that can be used by the calling process. 
    The function reserves space in the virtual address space of the process and allocates physical storage for a specified initial portion of this block
    
    flOptions [in]:
    The heap allocation options. These options affect subsequent access to the new heap through calls to the heap functions. This parameter can be 0 or one or more of the following values.
    HEAP_CREATE_ENABLE_EXECUTE:
    All memory blocks that are allocated from this heap allow code execution
    HEAP_GENERATE_EXCEPTIONS:
    The system raises an exception to indicate failure (for example, an out-of-memory condition) for calls to HeapAlloc and HeapReAlloc instead of returning NULL.
    HEAP_NO_SERIALIZE:
    Serialized access is not used when the heap functions access this heap.
    
    //备注
    Serialization ensures mutual exclusion when two or more threads attempt to simultaneously allocate or free blocks from the same heap. 
    There is a small performance cost to serialization, but it must be used whenever multiple threads allocate and free memory from the same heap.
    Setting the HEAP_NO_SERIALIZE value eliminates mutual exclusion on the heap. Without serialization,
    two or more threads that use the same heap handle might attempt to allocate or free memory simultaneously, likely causing corruption in the heap. 
    堆的序列化访问开销很小且能保证堆安全,所以一般不使用 HEAP_NO_SERIALIZE
    
    dwInitialSize [in]
    The initial size of the heap, in bytes. This value determines the initial amount of memory that is committed for the heap. 
    The value is rounded up to a multiple of the system page size. The value must be smaller than dwMaximumSize.
    If this parameter is 0, the function commits one page. To determine the size of a page on the host computer, use the GetSystemInfo function.
    
    dwMaximumSize [in]
    The maximum size of the heap, in bytes. 
    The HeapCreate function rounds dwMaximumSize up to a multiple of the system page size and then reserves a block of that size in the process's virtual address space for the heap. 
    If allocation requests made by the HeapAlloc or HeapReAlloc functions exceed the size specified by dwInitialSize, the system commits additional pages of memory for the heap, up to the heap's maximum size.
    If dwMaximumSize is not zero, the heap size is fixed and cannot grow beyond the maximum size. 
    Also, the largest memory block that can be allocated from the heap is slightly less than 512 KB for a 32-bit process and slightly less than 1,024 KB for a 64-bit process. 
    Requests to allocate larger blocks fail, even if the maximum size of the heap is large enough to contain the block.
    If dwMaximumSize is 0, the heap can grow in size. The heap's size is limited only by the available memory. 
    Requests to allocate memory blocks larger than the limit for a fixed-size heap do not automatically fail; instead, 
    the system calls the VirtualAlloc function to obtain the memory that is needed for large blocks. Applications that need to allocate large memory blocks should set dwMaximumSize to 0.
    
    If the function succeeds, the return value is a handle to the newly created heap.
    If the function fails, the return value is NULL
    (B):
    LPVOID WINAPI HeapAlloc
    (
    	__in HANDLE hHeap,
    	__in DWORD dwFlags,		//可以为0
    	__in SIZE_T dwBytes
    );
    Allocates a block of memory from a heap. The allocated memory is not movable.
    
    dwFlags [in]:
    The heap allocation options. Specifying any of these values will override the corresponding value specified when the heap was created with HeapCreate.
    This parameter can be one or more of the following values.
    HEAP_GENERATE_EXCEPTIONS:
    The system will raise an exception to indicate a function failure, such as an out-of-memory condition, instead of returning NULL.
    To ensure that exceptions are generated for all calls to this function, specify HEAP_GENERATE_EXCEPTIONS in the call to HeapCreate.
    In this case, it is not necessary to additionally specify HEAP_GENERATE_EXCEPTIONS in this function call.
    HEAP_NO_SERIALIZE:
    Serialized access will not be used for this allocation. For more information, see Remarks.
    To ensure that serialized access is disabled for all calls to this function, specify HEAP_NO_SERIALIZE in the call to HeapCreate. 
    In this case, it is not necessary to additionally specify HEAP_NO_SERIALIZE in this function call.
    This value should not be specified when accessing the process's default heap. The system may create additional threads within the application's process, 
    such as a CTRL+C handler, that simultaneously access the process's default heap.
    HEAP_ZERO_MEMORY:
    The allocated memory will be initialized to zero. Otherwise, the memory is not initialized to zero.
    
    dwBytes [in]:
    The number of bytes to be allocated.
    If the heap specified by the hHeap parameter is a "non-growable" heap, dwBytes must be less than 0x7FFF8. 
    You create a non-growable heap by calling the HeapCreate function with a nonzero value.
    
    If the function succeeds, the return value is a pointer to the allocated memory block.
    If the function fails and you have not specified HEAP_GENERATE_EXCEPTIONS, the return value is NULL.
    If the function fails and you have specified HEAP_GENERATE_EXCEPTIONS, the function may generate either of the exceptions listed in the following table. 
    The particular exception depends upon the nature of the heap corruption. 
    (C):
    BOOL WINAPI HeapFree
    (
    	_In_ HANDLE hHeap,
    	_In_ DWORD  dwFlags,	//0 或者 HEAP_NO_SERIALIZE
    	_In_ LPVOID lpMem
    );
    Frees a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function.
    	
    If the function succeeds, the return value is nonzero.
    If the function fails, the return value is zero
    (D):
    BOOL WINAPI HeapDestroy(_In_ HANDLE hHeap);
    Destroys the specified heap object. It decommits and releases all the pages of a private heap object, and it invalidates the handle to the heap.
    (E):
    LPVOID WINAPI HeapReAlloc
    (
    	_In_ HANDLE hHeap,
    	_In_ DWORD  dwFlags,	//0, HEAP_GENERATE_EXCEPTIONS, HEAP_NO_SERIALIZE, HEAP_ZERO_MEMORY, HEAP_REALLOC_IN_PLACE_ONLY
    	_In_ LPVOID lpMem,
    	_In_ SIZE_T dwBytes
    );
    Reallocates a block of memory from a heap. This function enables you to resize a memory block and change other memory block properties. The allocated memory is not movable.
    
    HEAP_REALLOC_IN_PLACE_ONLY:	
    There can be no movement when reallocating a memory block. If this value is not specified, the function may move the block to a new location. 
    If this value is specified and the block cannot be resized without moving, the function fails, leaving the original memory block unchanged.
    
    HeapReAlloc is guaranteed to preserve the content of the memory being reallocated, even if the new memory is allocated at a different location. 
    The process of preserving the memory content involves a memory copy operation that is potentially very time-consuming.
     
    函数返回类似于 HeapAlloc
    (H):
    SIZE_T WINAPI HeapSize
    (
    	_In_ HANDLE  hHeap,
    	_In_ DWORD   dwFlags,	//0 HEAP_NO_SERIALIZE
    	_In_ LPCVOID lpMem
    );
    Retrieves the size of a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function.
    
    (I):
    #include <Windows.h>
    #include <assert.h>
    
    //32项目
    void Test0()
    {
    	HANDLE hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 1024 * 1024);
    	if (hHeap)
    	{
    		char* pMemory = static_cast<char*>(HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 512 * 1024));	//pMemory = 0x00000000 <错误的指针>
    		if (!HeapFree(hHeap, HEAP_NO_SERIALIZE, pMemory) || !HeapDestroy(hHeap))
    		{
    			assert(false);
    		}
    	}
    	//程序会正常退出
    }
    
    void Test1()
    {
    	HANDLE hHeap = HeapCreate(0, 0, 0);
    	if (hHeap)
    	{
    		char* pMemory0 = static_cast<char*>(HeapAlloc(hHeap, 0, 512));
    		for (int i = 0; i < 512; ++i)
    		{
    			pMemory0[i] = i;
    		}
    		char* pMemory1 = static_cast<char*>(HeapReAlloc(hHeap, 0, pMemory0, 512 * 1024));
    		const SIZE_T nSizeC = HeapSize(hHeap, 0, pMemory1);		//nSizeC = 524288
    		for (int i = 0; i < 512; ++i)
    		{
    			if (pMemory1[i] != static_cast<char>(i))
    			{
    				assert(false);
    			}
    		}
    		if (!HeapFree(hHeap, 0, pMemory1) || !HeapDestroy(hHeap))
    		{
    			assert(false);
    		}
    	}
    	//程序会正常退出
    }
    
    int main()
    {
    	Test0();
    	Test1();
    
    	LARGE_INTEGER aLarge[2] = {};
    
    	QueryPerformanceCounter(aLarge);
    	HANDLE hHeap = HeapCreate(0, 0, 0);
    	void* pMemory0 = HeapAlloc(hHeap, 0, 1024 * 1024 * 10);
    	QueryPerformanceCounter(aLarge + 1);
    	auto nRe0 = aLarge[1].QuadPart - aLarge[0].QuadPart;		//nRe0 = 288
    
    	QueryPerformanceCounter(aLarge);
    	char* pMemory1 = new char[1024 * 1024 * 10];
    	QueryPerformanceCounter(aLarge + 1);
    	auto nRe1 = aLarge[1].QuadPart - aLarge[0].QuadPart;		//nRe1 = 9289
    
    	HeapFree(hHeap, 0, pMemory0);
    	HeapDestroy(hHeap);
    	delete[] pMemory1;
    	return 0;
    }
    
    //4.
    其他常用堆函数:
    (A):GetProcessHeaps:得到进程地址空间多个堆的句柄
    (B):HeapValidate:验证堆的完整性
    (C):HeapCompact:让堆中闲置的内存块能重新结合在一起,并撤销调个堆中闲置内存块的存储器
    (D):HeapLock HeapUnlock:用于线程同步,一般不需要我们自己调用,堆函数内部一般会自动调用
    

      

  • 相关阅读:
    图片懒加载DEMO
    手写offset函数
    DOM
    jQuery笔记
    children和 childNodes辨析
    运算符...典型的三种用处
    Python中的数据结构---栈,队列
    手写call方法
    移动零元素--leetcode题解总结
    剑指 Offer 36. 二叉搜索树与双向链表
  • 原文地址:https://www.cnblogs.com/szn409/p/8541711.html
Copyright © 2011-2022 走看看