一個進程所能分配的最大內存是多大?這是由什麼決定的?

總內存為4GB,操作系統佔2GB,是不是一個進程能分到的最大內存就為2GB?還有什麼因素會影響嗎?


進程都是運行在虛擬地址空間的,對於Windows來說(Linux不太了解)虛擬地址範圍如下

32位普通模式 32位3G用戶模式 大小
起始--------結束 起始--------結束
空指針賦值區 00000000~0000FFFF 00000000~0000FFFF 64KB

用戶模式地址空間 00010000~7FFEFFFF 00010000~BFFEFFFF 約2GB或3GB

64K禁入區 7FFF0000~7FFFFFFF BFFF0000~BFFFFFFF 64KB

內核模式地址空間 80000000~FFFFFFFF C0000000~FFFFFFFF 2GB或1GB

64位模式 大小
起始-----------------------結束
空指針賦值區 00000000-00000000 00000000-0000FFFF 64KB

用戶模式地址空間 00000000-00010000 000007FF-FFFEFFFF 約8192GB

64K禁入區 000007FF-FFFF0000 000007FF-FFFFFFFF 64KB

內核模式地址空間 00000800-00000000 FFFFFFFF-FFFFFFFF -

所以,對於32位系統來說,沒有配置3GB用戶內存模式的情況下,用戶地址空間可用內存是2GB-128KB,內核可用內存是2GB。開啟以後,用戶地址空間可用內存是3GB-128KB

所以,在32位系統里,可能申請到的最大內存就是不到2GB,但實際情況更複雜一些,因為操作系統要記錄進程的內存使用情況,還要保存進程的入口、堆、線程棧等內容,這樣一來能申請到的內存不會達到2G這麼大。又考慮到大多數Windows程序的入口地址大概在0x10000~0x1000000之間,又因為可能有公共DLL佔用了一部分內存空間,所以實際上能申請的內存並不多。

--------------------------分割線--------------------------

以下代碼是用來顯示內存狀態的:

#include &
#include &

char * GetVMTypeString(DWORD type)
{
static char TypeString[256] = {0};

TypeString[0] = 0;

if (type MEM_IMAGE)
{
strcat(TypeString, "Image");
}
if (type MEM_MAPPED)
{
strcat(TypeString, "Mapped");
}
if (type MEM_PRIVATE)
{
strcat(TypeString, "Private");
}

return TypeString;
}

char * GetVMStateString(DWORD State)
{
static char StateString[256] = {0};

StateString[0] = 0;

if (State MEM_COMMIT)
{
strcat(StateString, "Commit");
}
if (State MEM_FREE)
{
strcat(StateString, "Free");
}
if (State MEM_RESERVE)
{
strcat(StateString, "Reserved");
}
return StateString;
}

char * GetVMAccessString(DWORD Access)
{
static char AccessString[12];

strcpy(AccessString, "-----------");

if (Access PAGE_NOACCESS)
{
AccessString[0] = "N";
}
if (Access PAGE_READONLY)
{
AccessString[1] = "R";
}
if (Access PAGE_READWRITE)
{
AccessString[2] = "W";
}
if (Access PAGE_WRITECOPY)
{
AccessString[3] = "C";
}
if (Access PAGE_EXECUTE)
{
AccessString[4] = "X";
}
if (Access PAGE_EXECUTE_READ)
{
AccessString[5] = "r";
}
if (Access PAGE_EXECUTE_READWRITE)
{
AccessString[6] = "w";
}
if (Access PAGE_EXECUTE_WRITECOPY)
{
AccessString[7] = "c";
}
if (Access PAGE_GUARD)
{
AccessString[8] = "G";
}
if (Access PAGE_NOCACHE)
{
AccessString[9] = "D";
}
if (Access PAGE_WRITECOMBINE)
{
AccessString[10] = "B";
}
return AccessString;
}
int main()
{
HANDLE hProc = GetCurrentProcess();
SIZE_T RetSize;
MEMORY_BASIC_INFORMATION mbi;
DWORD Addr = 0x0;
printf("Start End Size Protect Type State Access
");
while (TRUE)
{
ZeroMemory(mbi, sizeof(mbi));
RetSize = VirtualQueryEx(hProc, (LPCVOID)Addr, mbi, sizeof(mbi));

if (RetSize == 0)
break;

printf("0x%08X 0x%08X 0x%08X %c %-10s %-8s %s
",
mbi.BaseAddress,
(DWORD)mbi.BaseAddress + (mbi.RegionSize - 1),
mbi.RegionSize,
mbi.Protect ? "Y" : "N",
GetVMTypeString(mbi.Type),
GetVMStateString(mbi.State),
GetVMAccessString(mbi.AllocationProtect));

Addr += mbi.RegionSize;
}

return 0;
}

在我的PC上,以32位模式運行的結果是:

Start End Size Protect Type State Access
0x00000000 0x0000FFFF 0x00010000 Y Free -----------
0x00010000 0x0001FFFF 0x00010000 Y Mapped Commit --W--------
0x00020000 0x0002FFFF 0x00010000 Y Mapped Commit --W--------
0x00030000 0x0003FFFF 0x00010000 Y Free -----------
0x00040000 0x00040FFF 0x00001000 Y Image Commit -------c---
0x00041000 0x0004FFFF 0x0000F000 Y Free -----------
0x00050000 0x00056FFF 0x00007000 Y Mapped Commit -------c---
0x00057000 0x00057FFF 0x00001000 Y Mapped Commit -------c---
0x00058000 0x0005AFFF 0x00003000 Y Mapped Commit -------c---
0x0005B000 0x0005FFFF 0x00005000 Y Free -----------
0x00060000 0x00063FFF 0x00004000 Y Mapped Commit -R---------
0x00064000 0x0006FFFF 0x0000C000 Y Free -----------
0x00070000 0x00070FFF 0x00001000 Y Mapped Commit -R---------
0x00071000 0x0007FFFF 0x0000F000 Y Free -----------
0x00080000 0x00080FFF 0x00001000 Y Private Commit --W--------
0x00081000 0x000EFFFF 0x0006F000 Y Free -----------
0x000F0000 0x001E4FFF 0x000F5000 N Private Reserved --W--------
0x001E5000 0x001E5FFF 0x00001000 Y Private Commit --W--------
0x001E6000 0x001EFFFF 0x0000A000 Y Private Commit --W--------
0x001F0000 0x001FFFFF 0x00010000 Y Free -----------
0x00200000 0x00238FFF 0x00039000 N Private Reserved --W--------
0x00239000 0x0023BFFF 0x00003000 Y Private Commit --W--------
0x0023C000 0x0023FFFF 0x00004000 Y Private Commit --W--------
0x00240000 0x002A6FFF 0x00067000 Y Mapped Commit -R---------
0x002A7000 0x002BFFFF 0x00019000 Y Free -----------
0x002C0000 0x002C5FFF 0x00006000 Y Private Commit --W--------
0x002C6000 0x0033FFFF 0x0007A000 N Private Reserved --W--------
0x00340000 0x003AFFFF 0x00070000 Y Free -----------
0x003B0000 0x003B5FFF 0x00006000 Y Private Commit --W--------
0x003B6000 0x003BFFFF 0x0000A000 N Private Reserved --W--------
0x003C0000 0x00401FFF 0x00042000 Y Private Commit --W--------
0x00402000 0x004BFFFF 0x000BE000 N Private Reserved --W--------
0x004C0000 0x0127FFFF 0x00DC0000 Y Free -----------
0x01280000 0x01280FFF 0x00001000 Y Image Commit -------c---
0x01281000 0x01290FFF 0x00010000 Y Image Commit -------c---
0x01291000 0x01294FFF 0x00004000 Y Image Commit -------c---
0x01295000 0x01296FFF 0x00002000 Y Image Commit -------c---
0x01297000 0x01298FFF 0x00002000 Y Image Commit -------c---
0x01299000 0x0129AFFF 0x00002000 Y Image Commit -------c---
0x0129B000 0x5891FFFF 0x57685000 Y Free -----------
0x58920000 0x58920FFF 0x00001000 Y Image Commit -------c---
0x58921000 0x58A30FFF 0x00110000 Y Image Commit -------c---
0x58A31000 0x58A32FFF 0x00002000 Y Image Commit -------c---
0x58A33000 0x58A33FFF 0x00001000 Y Image Commit -------c---
0x58A34000 0x58A37FFF 0x00004000 Y Image Commit -------c---
0x58A38000 0x58A42FFF 0x0000B000 Y Image Commit -------c---
0x58A43000 0x74A9FFFF 0x1C05D000 Y Free -----------
0x74AA0000 0x74AA0FFF 0x00001000 Y Image Commit -------c---
0x74AA1000 0x74AA3FFF 0x00003000 Y Image Commit -------c---
0x74AA4000 0x74AA4FFF 0x00001000 Y Image Commit -------c---
0x74AA5000 0x74AA7FFF 0x00003000 Y Image Commit -------c---
0x74AA8000 0x74AAFFFF 0x00008000 Y Free -----------
0x74AB0000 0x74AB0FFF 0x00001000 Y Image Commit -------c---
0x74AB1000 0x74AFDFFF 0x0004D000 Y Image Commit -------c---
0x74AFE000 0x74AFEFFF 0x00001000 Y Image Commit -------c---
0x74AFF000 0x74B01FFF 0x00003000 Y Image Commit -------c---
0x74B02000 0x74B02FFF 0x00001000 Y Image Commit -------c---
0x74B03000 0x74B0BFFF 0x00009000 Y Image Commit -------c---
0x74B0C000 0x74B0FFFF 0x00004000 Y Free -----------
0x74B10000 0x74B10FFF 0x00001000 Y Image Commit -------c---
0x74B11000 0x74B48FFF 0x00038000 Y Image Commit -------c---
0x74B49000 0x74B4AFFF 0x00002000 Y Image Commit -------c---
0x74B4B000 0x74B4EFFF 0x00004000 Y Image Commit -------c---
0x74B4F000 0x768FFFFF 0x01DB1000 Y Free -----------
0x76900000 0x76900FFF 0x00001000 Y Image Commit -------c---
0x76901000 0x76940FFF 0x00040000 Y Image Commit -------c---
0x76941000 0x76942FFF 0x00002000 Y Image Commit -------c---
0x76943000 0x76946FFF 0x00004000 Y Image Commit -------c---
0x76947000 0x76ACFFFF 0x00189000 Y Free -----------
0x76AD0000 0x76ADFFFF 0x00010000 Y Image Commit -------c---
0x76AE0000 0x76BA0FFF 0x000C1000 Y Image Commit -------c---
0x76BA1000 0x76BAFFFF 0x0000F000 N Image Reserved -------c---
0x76BB0000 0x76BB0FFF 0x00001000 Y Image Commit -------c---
0x76BB1000 0x76BB1FFF 0x00001000 Y Image Commit -------c---
0x76BB2000 0x76BBFFFF 0x0000E000 N Image Reserved -------c---
0x76BC0000 0x76BC0FFF 0x00001000 Y Image Commit -------c---
0x76BC1000 0x76BCFFFF 0x0000F000 N Image Reserved -------c---
0x76BD0000 0x76BDAFFF 0x0000B000 Y Image Commit -------c---
0x76BDB000 0x76BDFFFF 0x00005000 N Image Reserved -------c---
0x76BE0000 0x770BFFFF 0x004E0000 Y Free -----------
0x770C0000 0x771B9FFF 0x000FA000 N Private Reserved ------w----
0x771BA000 0x771BFFFF 0x00006000 Y Free -----------
0x771C0000 0x772DEFFF 0x0011F000 N Private Reserved ------w----
0x772DF000 0x772DFFFF 0x00001000 Y Free -----------
0x772E0000 0x772E0FFF 0x00001000 Y Image Commit -------c---
0x772E1000 0x773E2FFF 0x00102000 Y Image Commit -------c---
0x773E3000 0x77411FFF 0x0002F000 Y Image Commit -------c---
0x77412000 0x77412FFF 0x00001000 Y Image Commit -------c---
0x77413000 0x77413FFF 0x00001000 Y Image Commit -------c---
0x77414000 0x77414FFF 0x00001000 Y Image Commit -------c---
0x77415000 0x77416FFF 0x00002000 Y Image Commit -------c---
0x77417000 0x77417FFF 0x00001000 Y Image Commit -------c---
0x77418000 0x77418FFF 0x00001000 Y Image Commit -------c---
0x77419000 0x7741AFFF 0x00002000 Y Image Commit -------c---
0x7741B000 0x7741DFFF 0x00003000 Y Image Commit -------c---
0x7741E000 0x77488FFF 0x0006B000 Y Image Commit -------c---
0x77489000 0x774BFFFF 0x00037000 Y Free -----------
0x774C0000 0x774C0FFF 0x00001000 Y Image Commit -------c---
0x774C1000 0x774CFFFF 0x0000F000 N Image Reserved -------c---
0x774D0000 0x775A5FFF 0x000D6000 Y Image Commit -------c---
0x775A6000 0x775AFFFF 0x0000A000 N Image Reserved -------c---
0x775B0000 0x775B0FFF 0x00001000 Y Image Commit -------c---
0x775B1000 0x775BFFFF 0x0000F000 N Image Reserved -------c---
0x775C0000 0x775C0FFF 0x00001000 Y Image Commit -------c---
0x775C1000 0x775C1FFF 0x00001000 Y Image Commit -------c---
0x775C2000 0x775C2FFF 0x00001000 Y Image Commit -------c---
0x775C3000 0x775C3FFF 0x00001000 Y Image Commit -------c---
0x775C4000 0x775C6FFF 0x00003000 Y Image Commit -------c---
0x775C7000 0x775C8FFF 0x00002000 Y Image Commit -------c---
0x775C9000 0x775CFFFF 0x00007000 N Image Reserved -------c---
0x775D0000 0x77626FFF 0x00057000 Y Image Commit -------c---
0x77627000 0x7762FFFF 0x00009000 N Image Reserved -------c---
0x77630000 0x77634FFF 0x00005000 Y Image Commit -------c---
0x77635000 0x7763FFFF 0x0000B000 N Image Reserved -------c---
0x77640000 0x7EF9FFFF 0x07960000 Y Free -----------
0x7EFA0000 0x7EFD2FFF 0x00033000 Y Mapped Commit -R---------
0x7EFD3000 0x7EFDAFFF 0x00008000 Y Free -----------
0x7EFDB000 0x7EFDDFFF 0x00003000 Y Private Commit --W--------
0x7EFDE000 0x7EFDEFFF 0x00001000 Y Private Commit --W--------
0x7EFDF000 0x7EFDFFFF 0x00001000 Y Private Commit --W--------
0x7EFE0000 0x7EFE4FFF 0x00005000 Y Mapped Commit -R---------
0x7EFE5000 0x7F0DFFFF 0x000FB000 N Mapped Reserved -R---------
0x7F0E0000 0x7FFDFFFF 0x00F00000 N Private Reserved -R---------
0x7FFE0000 0x7FFE0FFF 0x00001000 Y Private Commit -R---------
0x7FFE1000 0x7FFEFFFF 0x0000F000 Y Private Reserved -R---------

其中可以看到最大的一塊空閑內存是0x0129B000~0x5891FFFF 大概不到1.4GB


有些例外。使用AWE(address Window extension)可以讓進程在用戶態地址空間直接映射物理內存。這樣進程通過改變映射的方法就能使用最多64GB內存。SQL server就是這麼乾的。

當然這些都是歷史了。


2. 這是由什麼決定的?

答:由於進程屬於操作系統範圍的概念,而操作系統主要做的是對硬體資源的管理與控制,所以是一般是由操作系統和其管理/控制的硬體共同來決定的。

1. 一個進程所能分配的最大內存是多大?

答:先從硬體來看:主要看硬體所能支持的定址空間有多大,定址空間主要看的是地址匯流排的位數。

比如:32位PC機器,它的地址匯流排也是32位,可定址空間為2的32次方(4G)。

不過這只是最簡單的理解。像X86系列的CPU,有實模式保護模式之分,實模式是為了兼容以前老的8086CPU,在該模式下只能使用只有2的20次方(1M)的定址空間。

保護模式則可以有正常的4G定址空間。在奔騰Pro系列以及之後的CPU還添加了PAE功能,它能夠在32位基礎上實現更大的定址空間。

(如果想深入了解,請搜索上面的加粗詞語。)

再從操作系統來看:

a. 不提供虛擬內存:在這種情況下,操作系統暴露給進程的就是硬體級別的定址,進程中指定的任何內存地址都是真實的地址。那麼此時,進程所能分配的最大內存就是硬體所能支持的最大內存。

b. 提供虛擬內存:為了解決程序運行時的佔用內存大於機器實際內存、多進程下的進程保護等等問題,操作系統會抽象出一個虛擬內存來給進程使用,進程中指定的任何內存地址都是邏輯地址,會經過(操作系統+硬體)轉換為真實的地址。

此時進程所能分配的最大內存是由操作系統和硬體共同來決定的。

但上面說到進程中指定的任何內存地址都需要經過轉換成真實地址,那麼這種頻繁操作幾乎是不可能在操作系統這一層級實現的,所以大部分情況下還是為硬體所能支持的最大內存。

但是操作系統能夠控制分配給某個進程的虛擬內存最大的大小,硬體能夠支持4G,但我操作系統就允許你用1G的虛擬內存,你能耐我何。


拋個板磚,歡迎斧正:

《Windows程序設計》 王艷平版 第二章 2.1.2 虛擬內存

以32位Windows為例,最大內存定址空間為4G。

系統分前半部分(2G)作為進程私有空間;後半部分(2G)作為公用空間,用來存放內核代碼、驅動代碼、IO緩存區。


同一塊物理內存,可以被映射到不同虛擬空間,比如你的內核被映射到某個高位,位於內核空間中,同時內核中的頁表有可能被已只讀的方式映射到用戶空間中。這樣的話頁表對應的物理內存實際被重複映射了2次。所以說不是直接4-2=2的關係。


推薦閱讀:

從 Windows 95 開始一直在 shell32.dll 中存在的一個大樹圖標是出自哪裡?
為什麼操作系統的事件監聽不會佔用100%的CPU?
跑控制演算法究竟是裸奔(跑在中斷里)好還是操作系統好?
進程和線程有什麼區別?
如何評價在瀏覽器端實現Unix環境的Browsix框架?

TAG:操作系統 | 系統進程 |