日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何在32位程序中突破地址空间限制使用超过4G的内存

發(fā)布時間:2025/3/15 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何在32位程序中突破地址空间限制使用超过4G的内存 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

眾所周知,所有的32位應(yīng)用程序都有4GB的進程地址空間,因為32位地址最多可以映射4GB的內(nèi)存(對于虛擬地址空間概念不太熟悉的朋友建議去看一下《Windows核心編程》這本書)。對于Microsoft Windows操作系統(tǒng),應(yīng)用程序可以訪問2GB的進程地址空間(32位Linux可以訪問3GB地址空間),這就是稱為用戶模式的虛擬地址空間。這2GB的用戶模式虛擬地址空間位于4GB地址空間的低一半,而與之相對應(yīng)的高一半2GB地址空間由操作系統(tǒng)內(nèi)核使用,因此被成為內(nèi)核模式的虛擬地址空間。在一個進程中,所有的線程讀共享相同的2GB用戶模式虛擬地址空間。3 u/ C, p7 ]% w! [& t" D, b* O
? ? 對于一般的應(yīng)用程序來說,2GB的地址空間是足夠使用的了,但是對于一些特殊的需要使用海量內(nèi)存的應(yīng)用程序(典型的例子是數(shù)據(jù)庫系統(tǒng))來說,2GB的地址空間就遠遠不夠了。為了緩解地址空間的不足,微軟提供了一個權(quán)宜的解決方案,所有從Windows 2000 Server開始的操作系統(tǒng)版本都提供了一個boot.ini啟動開關(guān)(/3GB),可以為應(yīng)用程序提供訪問3GB的進程地址空間的能力,從而將內(nèi)核模式的地址空間限定為1GB。以下就是一個開啟了3GB選項的boot.ini文件示例:) e* M- e( W; v, t8 K$ Z4 L1 s6 e

[boot loader]

timeout=30; N/ b??]0 s6 j/ U$ e" J9 m+ a7 b4
default=multi(0)disk(0)rdisk(0)partition(1)WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)WINDOWS="Windows Server 2003, Enterprise" /fastdetect??/3GB


雖然使用/3GB選項能夠?qū)⒂脩裟J降牡刂房臻g擴大50%(從2GB增加到3GB),但是對于數(shù)據(jù)庫系統(tǒng)這樣的應(yīng)用程序來說,這1GB的地址空間的增加只能是杯水車薪,并不能解決多少問題,而且由于操作系統(tǒng)內(nèi)核只能使用1GB地址空間,這樣可能會給操作系統(tǒng)的運行帶來一定的負面影響,因此除非沒有更好的解決方案,是不建議使用/3GB方式的。% l/ O2 {& s6 j1 C
" Z; l$ Z/ ]??C

鑒于像數(shù)據(jù)庫系統(tǒng)這樣的應(yīng)用程序?qū)A績?nèi)存的需求,Intel公司也覺得4GB的內(nèi)存不夠用,因此就將CPU芯片中內(nèi)存地址線由32根擴展到了36根(即最多64GB),這就是所謂的物理地址擴展(PAE:Physical Address Extension)。PAE使得操作系統(tǒng)或應(yīng)用程序能夠最多使用64GB的物理內(nèi)存,對于Windows系統(tǒng)(2000以上)來說,只需在boot.ini文件中使用/PAE選項即可(類似于上面的/3GB選項)。需要提醒大家的是,如果沒有在boot.ini文件中使用/PAE選項,那么即使計算機已經(jīng)配置了超過4GB的物理內(nèi)存,在Windows操作系統(tǒng)中也不能使用超過4GB的那些內(nèi)存(事實上,根據(jù)我的經(jīng)驗,如果沒有使用/PAE選項,Windows系統(tǒng)最多只能識別3.25GB的物理內(nèi)存,我也不清楚為什么不是4GB?如果有知道的,請告訴我一聲)。( W% X3 E1 }: ?$ G+ C- f
? ? 雖然PAE使得在應(yīng)用程序中使用超過4GB的物理內(nèi)存成為可能,但是由于32位應(yīng)用程序的虛擬地址空間并不隨著物理內(nèi)存的增大而有任何變化,這意味著你不可能使用類似VirtualAlloc( GetCurrentProcess,2GB,...,...)這樣的函數(shù)=調(diào)直接分配接近用戶模式地址空間大小的內(nèi)存區(qū)域。為了突破32位地址空間的限制,需要使用一種被成為地址窗口擴展(AWE:Address Windowing Extensions)的機制(參見上圖)。& p2 {" y$ c. N. R' G4 S9 P* a
? ? AWE是Windows的內(nèi)存管理功能的一組擴展,它使應(yīng)用程序能夠使用的內(nèi)存量超過通過標準32位尋址可使用的2~3GB內(nèi)存。AWE允許應(yīng)用程序獲取物理內(nèi)存,然后將非分頁內(nèi)存的視圖動態(tài)映射到32位地址空間。雖然32位地址空間限制為4GB,但是非分頁內(nèi)存卻可以遠遠大于4GB。這使需要大量內(nèi)存的應(yīng)用程序(如大型數(shù)據(jù)庫系統(tǒng))能使用的內(nèi)存量遠遠大于32位地址空間所支持的內(nèi)存量。% Z% o. B1 K3 j
? ? 在使用AWE機制時,需要注意以下幾點:: f9 N5 r! P8 m* }5 l
? ? (1)AWE允許在32位體系結(jié)構(gòu)上分配超過4GB的物理內(nèi)存,只有當(dāng)系統(tǒng)可用物理內(nèi)存大于用戶模式的虛擬地址空間時,才應(yīng)該使用AWE。9 }/ f7 u9 `, m- P
? ? (2)若要使32位操作系統(tǒng)支持4GB以上的物理內(nèi)存,必須在Boot.ini文件啟用/PAE選項。
??? (3)若在Boot.ini文件中啟用了/3GB選項,則操作系統(tǒng)最多能夠使用16GB的物理內(nèi)存,因此如果實際的物理內(nèi)存超過16GB,必須確保不使用/3GB選項。
??? (4)使用AWE分配的內(nèi)存是非分頁的物理內(nèi)存,這意味著這部分內(nèi)存只能由分配的應(yīng)用程序獨占使用,不能由操作系統(tǒng)或其他程序使用,直到這些內(nèi)存被釋放為止,這與通常的VirtualAlloc函數(shù)分配的虛擬內(nèi)存存在顯著的不同,它不會參與分頁替換。3 l9 P* y5 S: I

?

在Windows中,跟AWE相關(guān)的API函數(shù)有以下幾個:# m) M# N. d. N( {5 W5 C9 ?5 M% ?2 C
/ a( `$ |$ u5 C??v7 r& h5 b

?

[cpp]?view plaincopy
  • BOOL?AllocateUserPhysicalPages(??
  • ??HANDLE?hProcess,??
  • ??PULONG_PTR?NumberOfPages,??
  • PULONG_PTR?UserPfnArray);??
  • ??
  • ??
  • BOOL?WINAPI?AllocateUserPhysicalPagesNuma(??
  • ??HANDLE?hProcess,??
  • ??PULONG_PTR?NumberOfPages,??
  • ??PULONG_PTR?PageArray,??
  • ??DWORD?nndPreferred);??
  • ??
  • ??
  • BOOL?MapUserPhysicalPages(??
  • ??PVOID?lpAddress,??
  • ??ULONG_PTR?NumberOfPages,??
  • ??PULONG_PTR?UserPfnArray);??
  • ??
  • BOOL?MapUserPhysicalPagesScatter(??
  • ??PVOID*?VirtualAddresses,??
  • ??ULONG_PTR?NumberOfPages,??
  • ??PULONG_PTR?PageArray??);??
  • ??
  • ??
  • BOOL?FreeUserPhysicalPages(??
  • ??HANDLE?hProcess,??
  • ??PULONG_PTR?NumberOfPages,??
  • ??PULONG_PTR?UserPfnArray);??

  • 各個函數(shù)的具體參數(shù)含義可以參考MSDN,其中AllocateUserPhysicalPagesNuma是Windows Vista和Windows 2008 Server新增的函數(shù),用于支持NUMA(非一致性內(nèi)存訪問)。以下就簡單說一下如何使用這幾個API函數(shù)來達到使用超過4GB的內(nèi)存。8 n/ E??r8 H! K+ }0 @5 R
    ? ? 使用AllocateUserPhysicalPages函數(shù)分配需要的物理內(nèi)存,使用方式如下:
    ULONG_PTR NumberOfPages = xxx; // 需要分配的內(nèi)存頁數(shù)
    ULONG_PTR *aPFNs? ?? ?? ?? ?? ?= new ULONG_PTR[NumberOfPages];
    BOOL bResult? ?? ?? ?? ?? ?? ?? ?? ?? ? = AllocateUserPhysicalPages( GetCurrentProcess(),&NumberOfPages,aPFNs);& \0 h$ H6 f3 R. Q* t

    ?檢查分配內(nèi)存是否成功
    if(!bResult)- |: j& k. G% x& R( }
    {$ D6 k. a5 I; s. s4 g) `
    ? ?// 分配識別,錯誤處理
    ? ?// .....8 ~5 B" {0 d' ~/ \1 F
    }6 T$ X1 u% E5 P

    檢查實際分配的內(nèi)存頁數(shù)$ \??U: S% w$ u' L- Z9 J
    if( NumberOfPages != xxx ): H4 z# e( R" N1 Z/ a4 N. |
    {
    ? ?// ....8 P' a- H( n??o6 L* c
    }
    需要注意的是,調(diào)用上述代碼的用戶必須具有“Lock Pages in Memory”(內(nèi)存中鎖定頁面)的權(quán)限。此權(quán)限使得用戶可以使用進程將數(shù)據(jù)保持在物理內(nèi)存中,這樣可防止系統(tǒng)將數(shù)據(jù)分頁到磁盤上的虛擬內(nèi)存中。行使此權(quán)限會因降低可用隨機存取內(nèi)存(RAM)的數(shù)量而顯著影響系統(tǒng)性能。需要在本地安全策略管理程序中給用戶賦予該權(quán)限,如下圖所示:
    .? ?0 E! @1 Y2 W; A/ X( u6 m, P+ v
    ? ? 給用戶分配了上述權(quán)限之后,需要在程序中使用代碼啟用該權(quán)限,如下所示:4 |( \7 k( P/ V" p1 ^; `8 `4 z
    7 @4 [1 g( X+ h8 x8 O) e+ M
    // 設(shè)置鎖住物理內(nèi)存的權(quán)限,此代碼在調(diào)用AllocateUserPhysicalPages之前執(zhí)行2 H% e9 U- p: ]; k9 P5 i
    if( !AWESetLockPagesPrivilege( GetCurrentProcess(), TRUE) ). }7 ~: \4 s( ?' ^
    {4 J: B0 W??@7 H& P3 {! S; X! m: B
    ? ? // 輸出錯誤信息

    }
    E" l/ A1 J
    ??? ///? ?? ???設(shè)置或清除啟用AWE( Address Windowing Extensions )所需要的鎖住內(nèi)存的權(quán)限。
    : E! |9 U. B
    ??? ///? ?? ???進程句柄。??y: S& R& q( q" w
    ?? ?///?7 D% m6 c$ K??H6 x! g8 x
    ? ? ///?
    ??? ///? ?? ???設(shè)置或者清除標志。
    ??? ///?( s* [- [! P5 ^8 G2 `0 D% u
    ??? ///?
    ??? ///? ?? ???如果成功,則返回TRUE,否則返回失敗。/ P) G) ^: `0 E0 i) R# s1 _+ O
    ? ? ///?5 r5 W: D8 E- g


    BOOL AWESetLockPagesPrivilege( HANDLE hProcess, BOOL Enable )
    {9 K, R' J( M+ \0 a
    ? ? HANDLE? ?? ?? ?? ?? ? Token? ? = NULL;# M* l, K0 g: X1 w2 E+ N+ j' _' e" m
    ? ? BOOL? ?? ?? ?? ?? ? Result? ? = FALSE;8 {& H1 n* O( H# V" U. d
    ? ? TOKEN_PRIVILEGES? ? Info? ? = { 0 };' v7 W7 ?8 g) `( Q" ?! o1 }
    6 r4 S5 D3 ^1 A( E
    ? ? // 打開令牌( h% ~% I7 W. G??h0 I
    ? ? Result = OpenProcessToken ( hProcess, TOKEN_ADJUST_PRIVILEGES, &Token );
    ?? ?if( !Result )??H& G2 B* y, N8 b9 P5 n$ D. A
    ? ?? ???return FALSE;

    ??? // 設(shè)置權(quán)限信息
    ?? ?Info.PrivilegeCount = 1;( B. M??N( Q6 _, c9 X; Z
    ? ? Info.Privileges[0].Attributes = Enable? SE_PRIVILEGE_ENABLED : 0;1 ?' B- d: ~# M

    ?? ?// 獲得鎖定內(nèi)存權(quán)限的ID$ w5 F; n- B) n/ c1 W' n??_9 r
    ? ? Result = LookupPrivilegeValue ( NULL,SE_LOCK_MEMORY_NAME,&(Info.Privileges[0].Luid));
    ??? if( !Result )?
    ??? {
    ?????? CloseHandle( Token );/ C5 ?; {4 F' p
    ? ?? ???return FALSE;5 j8 ^% \% s& S( _, o8 C5 C
    ? ? }2 C& E. I5 _2 T/ L/ [


    1 m# g' f- P$ h" C- d- X# c
    ? ? // 調(diào)整權(quán)限* A# o2 N* Q) K6 N1 ^) M9 e
    ? ? Result = AdjustTokenPrivileges ( Token, FALSE,(PTOKEN_PRIVILEGES) &Info,0, NULL, NULL);" ^! C: Y) l) T9 `& m2 o, W. U5 J
    ? ? if( ( !Result )??|| (??GetLastError() != ERROR_SUCCESS ) ); }# G* G. J. g5 V5 [+ D' Q8 }
    ? ? {3 d8 F" p6 l+ Q: L
    ? ?? ???CloseHandle( Token );
    ??????? return FALSE;. x3 m( ]/ h# A% t??T
    ? ? }


    ??? // 成功返回
    ?? CloseHandle( Token );. R0 O( Y0 @, w3 y
    ? ? return TRUE;& M+ K. J) Y4 X6 T% ]
    }

    使用AllocateUserPhysicalPages分配了物理內(nèi)存之后,下一步就是使用MapUserPhysicalPages或MapUserPhysicalPagesScatter函數(shù)將物理內(nèi)存映射進用戶模式地址空間內(nèi),這兩個函數(shù)用法差不多,只是第一個參數(shù)有差別。由于分配的物理內(nèi)存的大小超過了用戶模式地址空間的大小,因此顯然不可能一次將所有的物理內(nèi)存都映射到地址空間中。通常的做法是在用戶模式地址空間內(nèi)分配一小塊連續(xù)的區(qū)域(即地址窗口),然后根據(jù)使用的需要動態(tài)將部分的物理內(nèi)存映射到地址空間,這也就是“地址窗口擴展”一詞的真實含義。代碼示例如下:1 [) \. {??r7 B8 f3 o7 t
    ( [1 L& e+ e( e$ S1 I
    // 定義16M的地址窗口: ]: A. a9 i, Y2 v" ]( e: j
    #define MEMORY_REQUESTED (16*1024*1024)/ P, [- D! ^: Z* G$ H
    , e$ U5 L/ e$ |
    // 分配地址窗口# o$ n) o# S5 @4 S* z" p9 [
    PVOID lpMemReserved = VirtualAlloc( NULL,MEMORY_REQUESTED, MEM_RESERVE | MEM_PHYSICAL,PAGE_READWRITE );9 l/ a) [- B9 H( ]??v7 h3 R. j

    // 將物理內(nèi)存映射到地址空間(根據(jù)需要,每次映射的頁面會不同,
    // 即下面函數(shù)的第三個參數(shù)aPFNs會指向不同的物理頁)
    = MapUserPhysicalPages( lpMemReserved,NumberOfPages,aPFNs);
    // 以下就像普通的內(nèi)存一樣使用lpMemReserved 指針來操作物理內(nèi)存了
    使用完了之后,可以使用FreeUserPhysicalPages來釋放分配的物理內(nèi)存,示例如下:( V, Q4 C9 s8 L, o8 E2 U
    4 y" p3 @: C; Z4 o* ?

    // 取消內(nèi)存映射?6 O0 u" U& ]- G, p
    bResult = MapUserPhysicalPages( lpMemReserved,NumberOfPages,NULL );; B* a??q" H1 ^/ j" ]; ^0 J
    ??j) M! w4 m7 F, r

    // 釋放物理內(nèi)存: t$ A; V0 p9 b3 A: D! ]3 t
    bResult = FreeUserPhysicalPages( GetCurrentProcess(),&NumberOfPages,aPFNs );

    // 釋放地址窗口
    bResult = VirtualFree( lpMemReserved,0,MEM_RELEASE );

    // 釋放物理頁號數(shù)組/ w+ M& y5 M2 t, ]
    delete[] aPFNs;
    AWE機制被使用最多的一個場合是數(shù)據(jù)庫系統(tǒng)的緩存管理器(BufferManager),例如SQL Server的內(nèi)存管理器。雖然以上代碼都是基于Windows操作系統(tǒng),但是PAE和AWE機制并不是Windows特有的,32位linux也有類似的API。完整使用AWE機制的例子,大家可以參考MySQL的源碼。1 w??K* v- K% E6 w
    ? ? 最后想說的是,對于開發(fā)人員來說,一個好消息是64位CPU和操作系統(tǒng)正越來越普及。在64位環(huán)境下,一個進程的用戶模式的地址空間可達8TB(也就是說目前很多的64位系統(tǒng)只使用了40幾位的內(nèi)存地址,遠沒有充分使用64位的內(nèi)存地址),在可以預(yù)見的未來很長一段時間,估計我們都不會再為地址空間不足而發(fā)愁了,讓我們一起為64位時代的到來而歡呼吧!

    總結(jié)

    以上是生活随笔為你收集整理的如何在32位程序中突破地址空间限制使用超过4G的内存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。