进一步理解C++中的堆(Heap)

最近的项目涉及到Heap Corruption的问题,所以对堆要有更深的理解。

进程初始化时会被分配一个默认大小为1M的默认堆,这个堆会被很多重要的函数调用,比如当我们调用ANSI版本的某些函数时,它们的Unicode版本字符串就会存于其中。若应用程序中有多个线程都用到了默认堆,那么会有机制使得同时只能有一线程能在默认堆中进行操作。默认堆的分配和销毁都是由系统控制的,但是我们可以通过GetPreocessHeap()来得到本进程的默认堆句柄。

常用的分配函数有VirtualAlloc和HeapAlloc.VirtualAlloc请求4K为边界的整块虚拟内存,HeapAlloc分配任意大小的内存块。但后者是依赖前者实现的。也就是说在操作系统的层面上管理内存的最小单位是4K。要实现更小的内存管理(即HeapAlloc),需要用户态的程序自己去分配,比如说Windows的HeapManager。在分配时先用分配足够大的4K倍数的空间,再去进行内部的分配和回收。一般而言,对于小于1M的地址空间,我们一般使用HeapCreate(),但是更大的话,会倾向于用VirtualAlloc()在虚拟内存中分配。

以Alloc结尾的函数都只是分配堆空间,而真正的要去创建一个堆,要使用HeapCreate()。HeapCreate()会返回一个新堆的句柄,而各种alloc函数可以利用这个句柄在不同的堆空间上进行内存分配。在不同的堆上进行alloc可以有效的避免内存碎片的问题,因为当某一个堆中的内容不再需要时,我们可以将这个堆整个的HeapDestroy()掉。但是,若各种数据都存于一个堆中,则要Destroy整个堆必须保证所有的数据都不再需要。

当我们先把一个地址空间HeapFree之后,若HeapManager没有进行VirtualFree的操作,再次访问该地址操作系统并不会报错。因为以HeapFree和HeapAlloc都是由HeapManager来控制的,而操作系统一般情况下的界定粒度为4k。如果只是在HeapManager的控制范围内发生了越界,操作系统可能并不会认为这有什么错误。(因为没有在以4k为粒度的内存上越界)。

在各种create中,经常会有HEAP_NOSERIALIZE这个标志,它的作用是对堆进行线程访问控制。若这个标志被加到参数中,那么同一时刻,可以有多个线程对同一个堆进行堆操作。反之亦然。如果我们不用这个参数,还有两个可用函数HeapLock()和HeapUnlock()达到类似效果。

时间: 2024-08-31 05:10:57

进一步理解C++中的堆(Heap)的相关文章

进一步理解Python中的函数编程_python

我们最好从最难的问题开始:"到底什么是函数编程 (FP)?"一个答案可能会说 FP 就是您在使用例如 Lisp.Scheme.Haskell.ML.OCAML.Clean.Mercury.Erlang(或其它一些)语言进行编程时所做的.这是一个稳妥的答案,但不能很确切地阐明问题.不幸的是,即使是函数程序员他们自己也很难对 FP 究竟是什么有个一致的认识."盲人摸象"的故事用来形容这一情况似乎很合适.还可以放心地将 FP 与"命令编程"(使用例如

进一步理解Java中的多态概念_java

多态性有两种: 1)编译时多态性 对于多个同名方法,如果在编译时能够确定执行同名方法中的哪一个,则称为编译时多态性. 2)运行时多态性 如果在编译时不能确定,只能在运行时才能确定执行多个同名方法中的哪一个,则称为运行时多态性. 方法覆盖表现出两种多态性,当对象获得本类实例时,为编译时多态性,否则为运行时多态性,例如: XXXX x1 = new XXXX(参数列表); //对象获得本类实例,对象与其引用的实例类型一致 XXX xx1 = new XXX(参数列表); x1.toString();

仿STL中的堆算法的一个实现

RT. 堆的性质之类的不再这里阐述,写这个算法只为了更好的理解STL中的堆算法,如果看不懂STL中的算法也可以来参考这里给出的算法,因为是纯C的看起来会省去很多语言方面的细节. 同时里面还有一个STL中对应算法的测试以比较两者的效果. /******************************************************************** created: 2007/3/18 filename: main.cpp author: Lichuang purpose

基础才是重中之重~理解内存中的栈和堆

.NET中使用stack(栈)和heap(堆)两种结构在内存中存储数据,今天咱们就来说说这两个结构 Value Types,值类型      在C#中,值类型继承自System.ValueType的,它们分别是       Bool,   byte ,  char, decimal, double, enu, float, int, long, sbyte, short, struct, uint, ulong, ushort Reference Types 引用类型     引用类型包括所有的

C++:从栈和堆来理解C#中的值类型和引用类型

C++中并没有值类型和引用类型之说,标准变量或者自定义对象的存取默认是没有区别的.但如果深入地来看,就要了解C++中,管理数据的两大内存区域:栈和堆. 栈(stack)是类似于一个先进后出的抽屉.它的体积是有限的,一般为2M左右. 而堆(heap)则相对来说体积可以很大,这一般跟计算机的虚拟内存设置有关系. 栈中存取对象的内存是自动回收的,用完即销毁了,一般方法内部的变量和参数都是通过栈来存取的(但也正因为如此,它们的生命周期很短).但它的问题是,体积有限. 一些大的对象,我们可能要通过堆来创建

堆(heap)简介及实现

堆(heap)又被为优先队列(priority queue).堆并不是队列的子集.回忆一下,在队列中,我们限定的操作是dequeue和enqueue.其中dequeue是按照进入队列的先后顺序来取出元素.在堆中,我们不是按照元素进入队列的先后顺序取出元素的,而是按照元素的优先级取出元素. 这就好像候机的时候,无论谁先到达候机厅,总是头等舱的乘客先登机,然后是商务舱的乘客,最后是经济舱的乘客.每个乘客都有头等舱.商务舱.经济舱三种个键值(key)中的一个.头等舱->商务舱->经济舱依次享有从高到

跨考计算机求教,不理解操作系统中的一些概念

问题描述 跨考计算机求教,不理解操作系统中的一些概念 不太理解操作系统中的一些概念,想知道这样理解对不对.当一个程序运行时,需要显示结果到显示屏上,为I/O操作,切换到内核态,由于IO操作,该进程进入阻塞状态,系统调度其他进程运行.还系统调用到底是什么? 解决方案 只说Windows下的,(个人理解),别的系统大同小异学过汇编的都知道有种东西叫中断,分为可屏蔽和不可屏蔽的两种.但是Windows的设计者对中断进行了扩充,提出了一个叫"中断请求级"的概念.其中规定了32个中断请求级,其中

如何理解java中的某些方法不是线程安全的(不能同步访问)。

问题描述 如何理解java中的某些方法不是线程安全的(不能同步访问). 如何理解java中的某些方法不是线程安全的(不能同步访问). 能同步访问的方法有哪些,如何判断一个方法能不能同步访问 解决方案 不是线程安全的(不能同步访问) 你说反了.不是线程安全的才需要同步访问.同步访问的意思就是串行执行,等前面执行完了,再执行后面的. 线程不安全的场合很多,比如像操作系统中的用户界面.打印机等外设.控制台输出,都不允许并发(设想两个程序同时要输出文字到同一个屏幕,那还不乱套了) 在代码中,每个线程有自

纸上谈兵: 堆 (heap)

堆(heap)又被为优先队列(priority queue).尽管名为优先队列,但堆并不是队列.回忆一下,在队列中,我们可以进行的限定操作是dequeue和enqueue.dequeue是按照进入队列的先后顺序来取出元素.而在堆中,我们不是按照元素进入队列的先后顺序取出元素的,而是按照元素的优先级取出元素. 这就好像候机的时候,无论谁先到达候机厅,总是头等舱的乘客先登机,然后是商务舱的乘客,最后是经济舱的乘客.每个乘客都有头等舱.商务舱.经济舱三种个键值(key)中的一个.头等舱->商务舱->