• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++ Programmer's Cookbook

            {C++ 基礎} {C++ 高級} {C#界面,C++核心算法} {設計模式} {C#基礎}

            windows核心編程--虛擬內(nèi)存

            Wi n d o w s提供了3種進行內(nèi)存管理的方法,它們是:
            虛擬內(nèi)存,最適合用來管理大型對象或結構數(shù)組。

            內(nèi)存映射文件,最適合用來管理大型數(shù)據(jù)流(通常來自文件)以及在單個計算機上運行的多個進程之間共享數(shù)據(jù)。

            內(nèi)存堆棧,最適合用來管理大量的小對象。


            虛擬內(nèi)存的狀態(tài)
            Wi n d o w s函數(shù)G l o b a l M e m o r y S t a t u s可用于檢索關于當前內(nèi)存狀態(tài)的動態(tài)信息:
            VOID GlobalMemoryStatus(LPMEMORYSTATUS pmst);
            如果希望應用程序在內(nèi)存大于4 G B的計算機上運行,或者合計交換文件的大小大于4 G B,那么可以使用新的G l o b a l M e m o r y S t a t u s E x函數(shù):
            BOOL GlobalMemoryStatusEx(LPMEMORYSTATUSEX pmst);

            確定地址空間的狀態(tài)
            Wi n d o w s提供了一個函數(shù),可以用來查詢地址空間中內(nèi)存地址的某些信息(如大小,存儲器類型和保護屬性等)。
            這個函數(shù)稱為Vi r t u a l Q u e r y:
            DWORD VirtualQuery(
               LPCVOID pvAddress,
               PMEMORY_BASIC_INFORMATION pmbi,
               DWORD dwLength);
            Wi n d o w s還提供了另一個函數(shù),它使一個進程能夠查詢另一個進程的內(nèi)存信息:
            DWORD VirtualQueryEx(
               HANDLE hProcess,
               LPCVOID pvAddress,
               PMEMORY_BASIC_INFORMATION pmbi,
               DWORD dwLength);
            這兩個函數(shù)基本相同,差別在于使用Vi r t u a l Q u e r y E x時,可以傳遞你想要查詢的地址空間信息的進程的句柄。調(diào)試程序和其他實用程序使用這個函數(shù)最多,幾乎所有的應用程序都只需要調(diào)用Vi r t u a l Q u e r y函數(shù)。
            為了獲得完整的內(nèi)存信息,我創(chuàng)建了一個函數(shù),即V M Q u e r y:
            BOOL VMQuery(
               HANDLE hProcess,
               PVOID pvAddress,
               PVMQUERY pVMQ);
            系統(tǒng)信息

            許多操作系統(tǒng)的值是根據(jù)主機而定的,比如頁面的大小,分配粒度的大小等。這些值決不應該用硬編碼的形式放入你的源代碼。相反,你始終都應該在進程初始化的時候檢索這些值,并在你的源代碼中使用檢索到的值。G e t S y s t e m I n f o函數(shù)將用于檢索與主機相關的值:

             

            VOID GetSystemInfo(LPSYSTEM_INFO psinf);


            必須傳遞S Y S T E M _ I N F O結構的地址給這個函數(shù)。這個函數(shù)將初始化所有的結構成員然后返回。下面是S Y S T E M _ I N F O數(shù)據(jù)結構的樣子。

             

            typedef  struct  _SYSTEM_INFO
            {
               union
               
            {
                  DWORD dwOemId;  
            // Obsolete, do not use
                   struct  
                  
            {
                     WORD wProcessorArchitecture;
                     WORD wReserved;
                  }
            ;
               }
            ;
               DWORD     dwPageSize;
               LPVOID    lpMinimumApplicationAddress;
               LPVOID    lpMaximumApplicationAddress;
               DWORD_PTR dwActiveProcessorMask;
               DWORD     dwNumberOfProcessors;
               DWORD     dwProcessorType;
               DWORD     dwAllocationGranularity;
               WORD      wProcessorLevel;
               WORD      wProcessorRevision;
            }
             SYSTEM_INFO,  * LPSYSTEM_INFO;


            當系統(tǒng)引導時,它要確定這些成員的值是什么。對于任何既定的系統(tǒng)來說,這些值總是相同的,因此決不需要為任何既定的進程多次調(diào)用該函數(shù)。

            表14-1 與內(nèi)存有關的成員函數(shù)

            成員名 描述
            d w P a g e S i z e 用于顯示C P U的頁面大小。在x86 CPU上,這個值是4 0 9 6字節(jié)。在Alpha CPU 上,這個值是8 1 9 2字節(jié)。在I A - 6 4上,這個值是8 1 9 2字節(jié)
            l p M i n i m u m A p p l i c a t i o n A d d r e s s 用于給出每個進程的可用地址空間的最小內(nèi)存地址。在Windows 98上,這個值是4 194 304,或0 x 0 0 4 0 0 0 0 0,因為每個進程的地址空間中下面的4 M B是不能使用的。在Windows 2000上,這個值是65 536或0 x 0 0 0 1 0 0 0 0,因為每個進程的地址空間中開頭的6 4 K B總是空閑的
            l p M a x i m u m A p p l i c a t i o n A d d r e s s 用于給出每個進程的可用地址空間的最大內(nèi)存地址。在Windows 98 上,這個地址是2 147 483 647或0 x 7 F F F F F F F,因為共享內(nèi)存映射文件區(qū)域和共享操作系統(tǒng)代碼包含在上面的2 GB分區(qū)中。在Windows 2000上,這個地址是內(nèi)核方式內(nèi)存開始的地址,它不足6 4 K B
            d w A l l o c a t i o n G r a n u l a r i t y 顯示保留的地址空間區(qū)域的分配粒度。截止到撰寫本書時,在所有Wi n d o w s平臺上,這個值都是65536

            該結構的其他成員與內(nèi)存管理毫無關系,為了完整起見,下面也對它們進行了介紹(見表1 4 - 2)。

             

            表14-2 與內(nèi)存無關的成員函數(shù)

            成員名 描述
            d w O e m I d 已作廢,不引用
            W R e d e r v e d 保留供將來使用,不引用
            d w N u m b e r O f P r o c e s s o r s 用于指明計算機中的C P U數(shù)目
            d w A c t i v e P r o c e s s o r M a s k 一個位屏蔽,用于指明哪個C P U是活動的(允許運行線程)
            d w P r o c e s s o r Ty p e 只用于Windows 98,不用于Windows 2000,用于指明處理器的類型,如Intel 386、4 8 6或P e n t i u m
            w P r o c e s s o r A r c h i t e c t u r e 只用于Windows 2000,不用于Windows 98,用于指明處理的結構,如I n t e l、A l p h a、Intel 64位或Alpha 64位
            w P r o c e s s o r L e v e l 只用于Windows 2000,不用于Windows 98,用于進一步細分處理器的結構,如用于設定Intel Pentium Pro或Pentium II
            w P r o c e s s o r R e v i s i o n 只用于Windows 2000 ,不用于Windows 98,用于進一步細分處理器的級別

            在地址空間中保留一個區(qū)域

            通過調(diào)用Vi r t u a l A l l o c函數(shù),可以在進程的地址空間中保留一個區(qū)域:

             

            PVOID VirtualAlloc(
            PVOID pvAddress,
            SIZE_T dwSize,
            DWORD fdwAllocationType,
            DWORD fdwProtect);

            第一個參數(shù)p v A d d r e s s包含一個內(nèi)存地址,用于設定想讓系統(tǒng)將地址空間保留在什么地方。在大多數(shù)情況下,你為該參數(shù)傳遞M U L L。它告訴Vi r t u a l A l l o c,保存著一個空閑地址區(qū)域的記錄的系統(tǒng)應該將區(qū)域保留在它認為合適的任何地方。系統(tǒng)可以從進程的地址空間的任何位置來保留一個區(qū)域,因為不能保證系統(tǒng)可以從地址空間的底部向上或者從上面向底部來分配各個區(qū)域。可以使用M E M _ TO P _ D O W N標志來說明該分配方式。如果Vi r t u a l A l l o c函數(shù)能夠滿足你的要求,那么它就返回一個值,指明保留區(qū)域的基地址。如果傳遞一個特定的地址作為Vi r t u a l A l l o c的p v A d d r e s s 參數(shù),那么該返回值與傳遞給Vi r t u a l A l l o c的值相同,并被圓整為(如果需要的話) 6 4 K B邊界值。

            Vi r t u a l A l l o c函數(shù)的第二個參數(shù)是d w S i z e,用于設定想保留的區(qū)域的大小(以字節(jié)為計量單位)。由于系統(tǒng)保留的區(qū)域始終必須是C P U頁面大小的倍數(shù),因此,如果試圖保留一個跨越6 2 K B的區(qū)域,結果就會在使用4 KB、8 KB或16 KB頁面的計算機上產(chǎn)生一個跨越6 4 K B的區(qū)域。

            Vi r t u a l A l l o c函數(shù)的第三個參數(shù)是f d w A l l o c a t i o n Ty p e,它能夠告訴系統(tǒng)你想保留一個區(qū)域還是提交物理存儲器(這樣的區(qū)分是必要的,因為Vi r t u a l A l l o c函數(shù)也可以用來提交物理存儲器)。若要保留一個地址空間區(qū)域,必須傳遞M E M _ R E S E RV E標識符作為F d w A l l o c a t i o n Ty p e參數(shù)的值。


            最后一個參數(shù)是f d w P r o t e c t,用于指明應該賦予該地址空間區(qū)域的保護屬性。與該區(qū)域相關聯(lián)的保護屬性對映射到該區(qū)域的已提交內(nèi)存沒有影響。無論賦予區(qū)域的保護屬性是什么,如果沒有提交任何物理存儲器,那么訪問該范圍中的內(nèi)存地址的任何企圖都將導致該線程引發(fā)一個訪問違規(guī)。

            在保留區(qū)域中的提交存儲器

            當保留一個區(qū)域后,必須將物理存儲器提交給該區(qū)域,然后才能訪問該區(qū)域中包含的內(nèi)存地址。系統(tǒng)從它的頁文件中將已提交的物理存儲器分配給一個區(qū)域。物理存儲器總是按頁面邊界和頁面大小的塊來提交的。

            若要提交物理存儲器,必須再次調(diào)用Vi r t u a l A l l o c函數(shù)。不過這次為f d w A l l o c a t i o n Ty p e參數(shù)傳遞的是M E M _ C O M M I T標志,而不是M E M _ R E S E RV E標志。傳遞的頁面保護屬性通常與調(diào)用Vi r t u a l A l l o c來保留區(qū)域時使用的保護屬性相同(大多數(shù)情況下是PA G E _ R E A D W R I T E),不過也可以設定一個不同的保護屬性。

            在已保留的區(qū)域中,你必須告訴Vi r t u a l A l l o c函數(shù),你想將物理存儲器提交到何處,以及要提交多少物理存儲器。為了做到這一點,可以在p v A d d r e s s參數(shù)中設定你需要的內(nèi)存地址,并在d w S i z e參數(shù)中設定物理存儲器的數(shù)量(以字節(jié)為計量單位)。注意,不必立即將物理存儲器提交給整個區(qū)域。
            同時進行區(qū)域的保留和內(nèi)存的提交

            有時你可能想要在保留區(qū)域的同時,將物理存儲器提交給它。只需要一次調(diào)用Vi r t u a l A l l o c函數(shù)就能進行這樣的操作,如下所示:

             

            PVOID pvMem  =  VirtualAlloc(NULL,  99   *   1024 ,   MEM_RESERVE  |  MEM_COMMIT, PAGE_READWRITE);


            這個函數(shù)調(diào)用請求保留一個99 KB的區(qū)域,并且將99 KB的物理存儲器提交給它。當系統(tǒng)處理這個函數(shù)調(diào)用時,它首先要搜索你的進程的地址空間,找出未保留的地址空間中一個地址連續(xù)的區(qū)域,它必須足夠大,能夠存放100 KB(在4 KB頁面的計算機上)或104 KB(在8 KB頁面的計算機上)。

            系統(tǒng)之所以要搜索地址空間,原因是已將p v A d d r e s s參數(shù)設定為N U L L。如果為p v A d d r e s s設定了內(nèi)存地址,系統(tǒng)就要查看在該內(nèi)存地址上是否存在足夠大的未保留地址空間。如果系統(tǒng)找不到足夠大的未保留地址空間,Vi r t u a l A l l o c將返回N U L L,

            如果能夠保留一個合適的區(qū)域,系統(tǒng)就將物理存儲器提交給整個區(qū)域。無論是該區(qū)域還是提交的內(nèi)存,都將被賦予PA G E _ R E A D W R I T E保護屬性。

            最后需要說明的是,Vi r t u a l A l l o c將返回保留區(qū)域和提交區(qū)域的虛擬地址,然后該虛擬地址被保存在p v M e m變量中。如果系統(tǒng)無法找到足夠大的地址空間,或者不能提交該物理存儲器,Vi r t u a l A l l o c將返回N U L L。
            回收虛擬內(nèi)存和釋放地址空間區(qū)域

            若要回收映射到一個區(qū)域的物理存儲器,或者釋放這個地址空間區(qū)域,可調(diào)用Vi r t u a l F r e e函數(shù):

             

            BOOL VirtualFree(
            LPVOID pvAddress,
            SIZE_T dwSize,
            DWORD fdwFreeType);

            改變保護屬性

            雖然實踐中很少這樣做,但是可以改變已經(jīng)提交的物理存儲器的一個或多個頁面的保護屬性。

            若要改變內(nèi)存頁面的保護屬性,可以調(diào)用Vi r t u a l P r o t e c t函數(shù):

             

                BOOL VirtualProtect(
               PVOID pvAddress,
               SIZE_T dwSize,
               DWORD flNewProtect,
               PDWORD pflOldProtect);


            當然,保護屬性是與內(nèi)存的整個頁面相關聯(lián)的,而不是賦予內(nèi)存的各個字節(jié)的。因此,如果要使用下面的代碼來調(diào)用4 KB 頁面的計算機上的Vi r t u a l P r o t e c t函數(shù),其結果是把PA G E _ N O A C C E S S保護屬性賦予內(nèi)存的兩個頁面:

             

            VirtualProtect(pvRgnBase + (3 * 1024), 2 * 1024,
            PAGE_NOACCESS, &flOldProtect);

            清除物理存儲器的內(nèi)容


            為了說明內(nèi)存的內(nèi)容已經(jīng)被清除,我們必須對系統(tǒng)的R A M提出大量的使用需求。若要進行這項操作,可以分3步來進行:

            1) 調(diào)用G l o b a l M e m o r y S t a t u s函數(shù),獲取計算機中R A M的總容量。

            2) 調(diào)用Vi r t u a l A l l o c函數(shù),提交該數(shù)量的內(nèi)存。這項操作的運行速度非常快,因為在進程試圖訪問頁面之前,系統(tǒng)實際上并不為該內(nèi)存分配R A M。

            3) 調(diào)用Z e r o M e m o r y函數(shù),使新提交的頁面可以被訪問。這將給系統(tǒng)的R A M帶來沉重的負擔,導致當前正在R A M中的某些頁面被寫入頁文件。

            如果用戶指明該數(shù)據(jù)將在以后被訪問,那么該數(shù)據(jù)將不被清除,并且在以后訪問該數(shù)據(jù)時將數(shù)據(jù)轉入R A M。但是,如果用戶指明以后將不再訪問該數(shù)據(jù),那么數(shù)據(jù)將被清除,并且系統(tǒng)不把數(shù)據(jù)寫入頁文件,這樣就可以提高應用程序的運行性能。



             

            posted on 2006-09-20 18:12 夢在天涯 閱讀(3631) 評論(0)  編輯 收藏 引用 所屬分類: Windows API

            公告

            EMail:itech001#126.com

            導航

            統(tǒng)計

            • 隨筆 - 461
            • 文章 - 4
            • 評論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1804303
            • 排名 - 5

            最新評論

            閱讀排行榜

            久久久久一区二区三区| 久久精品一区二区三区AV| 亚洲狠狠婷婷综合久久久久| 99久久综合国产精品免费| 奇米影视7777久久精品| 久久91亚洲人成电影网站| 久久99亚洲综合精品首页| 久久婷婷五月综合国产尤物app | 亚洲va久久久噜噜噜久久| 国产精品久久影院| 久久综合色老色| 色综合久久久久网| 国内高清久久久久久| 久久精品国产亚洲7777| 久久久久亚洲av无码专区| 人人狠狠综合久久亚洲高清| 97精品伊人久久大香线蕉app| 久久综合亚洲鲁鲁五月天| 久久电影网2021| 久久久久人妻一区二区三区vr| 欧美久久久久久精选9999| .精品久久久麻豆国产精品| 久久受www免费人成_看片中文| 中文字幕亚洲综合久久| 久久久久国产精品熟女影院| 国产成人精品久久| 久久久SS麻豆欧美国产日韩| 久久伊人中文无码| 开心久久婷婷综合中文字幕| 99久久国产免费福利| 久久精品免费一区二区三区| 好久久免费视频高清| MM131亚洲国产美女久久| 国产精品一区二区久久精品涩爱| 久久无码一区二区三区少妇| 久久国产视频99电影| 久久久久亚洲AV无码专区网站| 国产精品免费久久久久影院| 激情五月综合综合久久69| 久久99热这里只有精品国产| 欧美无乱码久久久免费午夜一区二区三区中文字幕 |