堆是什么? 堆,也是一种操控内存的方法,它非常适合分配大量的小型数据,与虚拟内存、内存映射文件相比,是用来管理链表和树的最佳方式。但,堆的缺点是分配和释放内存块比其它方式要慢。在系统内部,堆是一块预订的地址空间区域,堆管理器所调拔的物理存储器是从页交换文件中分配的。释放堆中的内存块时,堆管理器会撤销已调拔的物理存储器。
1.进程的默认堆
所谓默认堆是指进程初始化时,系统会在进行的地址空间创建一个堆,默认大小是1MB,这个默认大小可以在创建应用程序时用/HEAP链接器开关来修改。
许多Windows 函数都使用到了进程的默认堆,进程的多线程调用各种Windows函数时,是必须依次进行的,也就是说要同步。系统会保证一次只让一个线程从默认堆中分配或释放内存块。 如果两个线程同时想要从默认堆中分配一块内存,那么只有线程A能够分配内存,线程B必须等待线程A分配完成。如果希望以最快的速度访问堆,可以创建额外的堆而不使用进程的默认堆。那么创建额外的堆有什么好处呢?会有以下这些:
1)对组件进行保护
如果 应用程序需要处理两个组件:一个由NODE结构组成的链表和一个由BRANCH结构组成的二叉树,如果 这两种结构都保存在一个堆中,混合在一起,假如链表的代码有缺陷,覆盖了NODE节点1后面的几个字节,就破坏BRANCH节点的数据。 如果是通过创建两个独立的堆,就不会有这种问题。
2)更有效的内存管理
可以减少内存碎片,因为每个堆里只包含同样大小的对象,释放一个对象后可以保证释放出的空间刚好能够容纳另一个对象。
3)局部访问
内存页面与页交换文件的换出、换入会产生较大性能影响,如果把内存访问局限在一个较小的地址区间内,将减少系统在内存和磁盘之间进行交换的可能性。使用同一个堆保存相同大小的对象,很有可能多个对象都落在同一个物理内存页面中。
4)避免线程同步的开销
上面提到,如果使用进程的默认堆,多线程时系统需保证堆的线程安全性,会产生性能影响。如果 是创建一个新的堆,且只有一个线程会访问堆时,就没同步的问题。但如果这个新堆,应用程序会有多线程访问的话,还是要保证对堆访问的线程安全性
5)快速释放
可以直接释放整个堆,而不需要对每个对象的内存块进行逐个释放。