lgxqf  

第十八章

1.

                虚拟内存主要用于分配连续的内存,如给大数组分配内存。
                堆主要用于分配小块内存, 如链表,树等就适合用堆来分配内存。
                优点在于:在堆中分配内存时不像虚拟内存要求那么多,如分配粒度、页边界等。它没有这些要求,可分配任意大小的内存。
                缺点在于:相对于其它内存分配机制,它分配和释放内存的速度较慢,而且失去了对内存commit和decommit的控制。
                一个进程中可以有多个堆。除默认堆外,其它堆都可以在进程生存期间创建或销毁
                进程的默认堆:用户不能销毁进程默认堆,因为在进程开始执行前,默认堆已经建立,进程结束后它会被自动销毁。
                堆中的内存分配操作是串行的,当有两个线程同时要在同一个堆中分配内存时,系统会先让一个线程执行分配内存操作,待其毕,再让第二个线程做分配内存操作。

 

2.创建其它堆的原因

                模块保护:把不同的类重要数据放在不同的堆中,可以防止对其中一种数据进行写操作发生内存溢出时覆盖其它类数据的内容。
                              如:有一个链表和一棵树,若将它们的内存都放在同一个堆中,那么当对链表的内存操作有写溢出时可能会覆盖树中的内容

                                    把链表和树分别放在不同的堆中就可以保证链表的写溢出操作不会影响树中的数据。

                有效的内存管理:在堆中仅分配相同大小的对象有利用提高内存使用率,避免产生内存碎片。
                              如:有10字节大小的堆,其中有两个2字节的对象,两个3字节的对象。此时内存已满。当释放两个不连续2字节的对象时
                              此时有4字节的空间可用,但由于不连续,就产生了内存碎片。 当需要3字节的连续空间时就无法提供足够的内存。 

                本地存储: 把可能被同时访问的数据连续放在一起(同一页中),提要减少换页操作和页的访问次数,有利于提高效率

                避免线程同步开销:当多线程同时对同一堆进行操作时,堆函数需要执行额外的代码来同步线程的访问,这此额外执行的代码会对程序的性能造成影响。
                                         当我们为新建堆时可以告诉系统,该堆只会被一个线程访问,这样堆函数就不会执行额外的代码,从而提高了系统的性能。

                                         此时由用户来控制堆的线程安全,可以用互拆量等对线程操作堆的操作进行同步

 
                快速释放内存:为某些数据结构指定专用堆,允许我们对整个堆进行释放操作,而无需一块块地释放堆中的内存。
        
3.如何创建额外的堆   

               若要分配大量内存,如1M或更多,建议用VirtualAlloc来分配内存而不是在堆中分配内存

               创建堆函数 HANDLE HeatCreate(DWORD, fwdOptions
                                               SIZE_T dwInitialSize,
                                               SIZE_T dwMaximumSize)
               在创建堆时尽量不要用fwdOptions,设为HEAP_NO_SERIALIZE,除非以下三种情况:
                                (1)进程中只有一个线程
                                (2)多线程中确保只有一个线程会对该堆进行操作
                                (3)多线程中用户通过互斥机制来同步不同线程对堆的操作
               dwInitialSize是堆在最开始是commit的内存大小(页大小4KB的倍数)
               dwMaximumSize是堆可以增长的最大值,若将其设为0,那么堆可以增长直至用完所有内存。

 

4.堆中分配内存的步骤             

              (1)遍历已分配内存和未分配内存的内存块的链表

              (2)找到一块足够大的内存模块

              (3)在找到的内存模块上分配内存,并将其标记为已分配

              (4)在内存链表中加入新的条目

5.Common API:

              HeapCreate             HeapSize HeapReAlloc

              HeapFree                HeapDestroy                           GetProcessHeaps 取得堆的句柄

              HeapValidate           HeapCompact

              HeapLock                HeapUnlock

              HeapWalk

posted on 2009-03-18 13:52  Justin_Ma  阅读(290)  评论(0编辑  收藏  举报