
此系統資訊來自 Process Explorer。仍然有可用的物理內存,但係統顯示幾乎沒有剩餘 RAM。
任務管理器也顯示總 RAM 的使用量約為 74%。
自從 Windows 8.1 安裝以來,電腦擁有 4+8=12 GB RAM。我透過將 4 GB 模組更改為 8 GB 模組來對其進行升級。這可能是問題所在嗎?或者這種行為是否正常,我只是誤解了可用物理記憶體的含義?
答案1
簡答
「記憶體不足」彈出視窗表示您已超出記憶體限制私人承諾記憶體——虛擬記憶體的一種。並不是說您的 RAM(實體記憶體)用完了。多少並不重要可用的你有內存。擁有大量可用 RAM 不允許您超出提交限制。提交限制是您的總和 全部的RAM(無論是否使用!)加上您目前的頁面檔案大小。
相反,「用完」提交限制(主要是建立進程私有虛擬位址空間)不一定使用任何 RAM!但是作業系統不會允許它的創建,除非它知道有地方可以在需要時儲存它。因此,您可以在不使用所有 RAM 甚至大部分 RAM 的情況下遇到提交限制。
這就是為什麼你不應該在沒有頁面文件的情況下運行。請注意,頁面文件實際上可能不會被寫入!但它仍然可以讓您避免“內存不足”和“內存不足”錯誤。
中級答案
Windows 其實並沒有 RAM 不足的錯誤訊息。你所用的就是「提交限制」。
該版本的 Process Explorer 中的「系統」圖的命名很糟糕。它應該被標記為「承擔費用」。 (在我的版本中,它被稱為“系統提交”。更好,但仍然不完全一致。)在任何情況下,圖形的“當前”高度在文本部分的下方顯示為“提交費用”-“目前”,圖表的最大高度代表“Commit Charge”-“Limit”。
「提交費用」是指由頁面檔案支援的虛擬位址空間(如果有的話)——換句話說,如果它不能全部放入 RAM,則剩餘部分將放入頁面檔案中。 (還有其他類型的vas,它們要么由其他文件支援- 這稱為“映射”vas - 或必須始終保留在RAM 中;後者稱為“不可分頁”。)“提交限制”是可允許的最大值。它等於 RAM 大小加上頁面檔案大小。
您顯然沒有頁面文件(我可以看出,因為您的提交限制等於您的 RAM 大小),因此提交限制只是 RAM 大小。
顯然,各種程式+作業系統幾乎使用了所有可能的最大提交。
這與有多少空閒或可用 RAM 沒有直接關係。是的,您有大約 4.5 GB 的可用 RAM。這並不意味著您可以超出提交限制。提交的記憶體不一定使用 RAM,也不受可用 RAM 量的限制。
您需要重新啟用頁面文件 - 使用這麼多提交的內容,我建議使用 16 GB 頁面文件,因為您不想強製操作系統將這麼多內容保留在 RAM 中,並且頁面文件如果滿足以下條件,效果最好有很多可用空間- 或增加更多RAM。多很多。為了獲得良好的效能,您需要在 RAM 中有足夠的空間來存放程式碼和其他不受頁面檔案支援的內容(但可以分頁到其他檔案)。
很長的答案
(但仍比記憶體管理章節短很多Windows 內部架構...)
假設一個程式分配了 100 MB 進程私有虛擬記憶體。這是透過帶有“commit”選項的 VirtualAlloc 呼叫來完成的。這將導致「提交費用」增加 100 MB。但這個「分配」其實並沒有使用任何RAM!僅當其中一些新提交時才使用 RAM虛擬位址空間是第一次訪問。
RAM 最終如何使用
(如果有的話)
首次存取新提交的空間幾乎總是記憶體寫入(在寫入之前讀取新分配的私有 vas 幾乎總是編程錯誤,因為嚴格來說,其初始內容是未定義的)。但讀或寫,第一次接觸新分配的 vas 的頁面時,結果是頁面錯誤。儘管「錯誤」這個詞聽起來很糟糕,但頁面錯誤是虛擬記憶體作業系統中完全可以預料到甚至是必需的事件。
為了回應這種特定類型的頁面錯誤,分頁器(作業系統記憶體管理器的一部分,我有時將其縮寫為“Mm”)將:
- 分配 RAM 的實體頁(理想情況下從零頁列表,但無論如何,它來自 Windows 所謂的「可用」:零頁、空閒頁或備用頁列表,按優先順序排列);
- 填寫一個頁表項將實體頁與虛擬頁關聯起來;最後
- 消除頁面錯誤異常。
之後,執行記憶體引用的程式碼將重新執行引發頁面錯誤的指令,這次引用將會成功。
我們說該頁面已「故障」到進程工作集和 RAM 中。在工作管理員中,這將顯示為進程的「專用工作集」中一頁 (4 KB) 的增加。可用實體記憶體減少一頁。 (後者在繁忙的機器上可能很難注意到。)
註1:此頁面錯誤不涉及從磁碟讀取任何內容。從未訪問過的已提交虛擬記憶體頁不會在磁碟上開始生命週期;磁碟上沒有空間可以讀取它從。它只是「具體化」在 RAM 的先前可用頁面中。事實上,從統計數據來看,大多數頁面錯誤都是在RAM 中解決的,要么是已在RAM 中供其他進程使用的共享頁面,要么是頁面緩存(備用或修改列表),或者是像這樣的「零需求」頁面。
筆記2:這僅需要“可用”中的一頁,即 4096 位元組。提交之前從未觸及的地址空間通常一次僅實現一個頁面(出現故障),因為每個頁面都是第一次「觸及」。一次做得越多,不會有什麼進步,也沒有什麼好處;只需要n倍的時間。相較之下,當必須從磁碟讀取頁面時,會嘗試一定量的“預讀”,因為磁碟讀取的絕大多數時間都在每個操作的開銷中,而不是實際的資料傳輸。 「承諾」量維持在 100 MB;一個或多個頁面發生故障這一事實並不會減少提交費用。
註3:假設我們有 4 GB「可用」RAM。這意味著在 RAM 耗盡之前,我們可以再引用已分配但從未引用過的提交記憶體大約一百萬次 (4 GB / 4096)。此時,如果我們有一個符合 David Cutler 和 Lou Perazzoli 預期的頁面文件,RAM 中一些最早引用的頁面將被保存在磁碟上,然後可用於解決這些最近的頁面錯誤。 (實際上,作業系統會在此之前啟動諸如「工作集修剪」之類的RAM 回收方法,並且對頁面檔案的實際寫入會在修改後的頁面清單上進行快取和批次處理,以提高效率,並且......)這些都不會影響「承諾」計數。不過,它與「提交限制」有關。如果 RAM 中沒有空間容納所有「已提交」內存,則多餘的內存可以保留在頁面文件中。因此,頁面文件的大小會影響「提交限制」。
而且這種事一直在發生…
但假設我們還沒有完成那百萬次引用,並且仍然有大約 4GB 的頁面「可用」。現在讓我們假設同一個進程(或另一個進程,都沒關係)執行另一個 VirtualAlloc,這次提交了 200 MB。同樣,這 200 MB 會添加到提交費用中,並且不會刪除任何可用 RAM。簡單地 VirtualAlloc'ating 位址空間不會使用相應數量的 RAM,並且具有較低的「可用」RAM 不會限制您可以 VirtualAlloc 的位址空間量(具有較高的可用 RAM 也不會增加它)。
(嗯,好吧……有一點點開銷,相當於每 2 MB(如果在 x86、非 PAE 系統上,則為 4 MB)用於頁表的一個(可分頁!)頁面分配的虛擬地址空間,並且每個虛擬連續的分配範圍都有一個幾十字節的「虛擬位址描述符」。
透過這種方式,這是可能的——而且是常見的! - 在僅使用少量 RAM 的情況下消耗大量「承諾費用」。
那麼,如果「提交」虛擬位址空間不會耗盡 RAM,為什麼還要有限制呢?
因為「承諾費用」確實代表了潛力未來儲存空間的使用。 「提交限制」表示可用於保存此類分配的儲存總量(RAM + 頁面檔案空間),如果它們實際上被引用並且需要儲存在某個地方。
當 Mm 批准 VirtualAlloc 請求時,它承諾 - “做出承諾” - 對分配區域的所有後續記憶體存取都將成功;它們可能會導致頁面錯誤,但這些錯誤都可以解決,因為有足夠的儲存空間來保存所有這些頁面的內容,無論是在 RAM 中還是在頁面檔案中。 Mm 知道這一點,因為它知道有多少儲存空間(提交限制)以及已經「提交」了多少(當前提交費用)。
(但所有這些頁面不一定都已被訪問,因此在任何給定時間不一定有實際的儲存量與提交的數量相符。)
那麼...「系統記憶體不足」怎麼辦?
如果您嘗試 VirtualAlloc 並且當前提交費用加上請求的分配大小將使您超過提交限制,並且操作系統無法擴展頁面文件以增加提交限制...您會收到“內存不足”彈出訊息 -啟動,進程看到VirtualAlloc 呼叫失敗。大多數程序此時都會舉手而死。有些人會盲目地繼續,假設呼叫成功,然後當他們嘗試引用他們認為分配的區域時會失敗。
再次(抱歉重複):您有多少可用 RAM 並不重要。作業系統已承諾 RAM 或頁面檔案空間將要在需要時可用,但該承諾不會從「可用」中減去。可用 RAM 僅在提交時被已提交的虛擬機器用完引用的第一次,這就是導致它「出錯」的原因……即在物理記憶體中實現。簡單地提交(=分配)虛擬記憶體並不能做到這一點。它只佔用空閒的虛擬位址空間並從中產生可用的虛擬位址空間。
但在「記憶體不足」的情況下,存在已提交記憶體的分配請求,並且作業系統已將當前提交費用添加到此新請求的大小中......並發現總數為更多的超過提交限制。所以如果作業系統批准了這個新的,和之後所有空間都被引用,不會有任何實際位置(RAM + 頁面檔案)來儲存所有空間。
作業系統不允許這樣做。在最壞的情況下,它不會允許分配比其容納空間更多的 vas - 即使所有 vas 都「故障」。這就是「提交限制」的目的。
我告訴你三次我告訴你三次我告訴你三次:「可用」RAM 的數量並不重要。提交的虛擬空間實際上尚未使用所有儲存空間,這並不重要。 Windows 無法「提交」虛擬分配,除非它將來「可能」出現故障。
注意,還有另一種類型的 vas 稱為“mapped”,主要用於代碼和訪問大型數據文件,但它不收取“commit charge”,也不受“commit limit”的限制。這是因為它有自己的儲存區域,即「映射」到它的檔案。 「映射」vas 的唯一限制是用於映射檔案的磁碟空間量,以及進程中用於將它們映射到的空閒 vas 量。
但是當我查看系統時,我還沒有完全達到提交限制?
這基本上是一個測量和記錄保存問題。您正在嘗試 VirtualAlloc 呼叫但失敗後查看系統。
假設您只剩下 500 MB 的提交限制,並且某些程式嘗試 VirtualAlloc 600 MB。嘗試失敗了。然後你看著系統說“什麼?還剩 500 MB!”事實上,到那時可能還剩下很多,因為到那時相關進程可能已經完全消失,因此所有先前分配的提交記憶體都已被釋放。
問題是你無法及時回顧並查看提交費用曾是此時正在嘗試分配。而且您也不知道該嘗試需要多少空間。因此,您無法明確地了解嘗試失敗的原因,或者需要多少「提交限制」才能使其正常運作。
我看過「系統是低位運行靠記憶」。那是什麼?
如果在上述情況下,作業系統可以擴展頁面檔案(即,您將其保留為預設的「系統管理」設置,或者您對其進行管理,但將最大值設為大於初始值,並且有足夠的可用磁碟空間),而這種擴充功能充分增加了提交限制,使 VirtualAlloc 呼叫成功,然後... Mm 擴充頁面文件,VirtualAlloc 呼叫成功。
這時您會看到「系統記憶體不足」。這是一個早期警告,如果事情繼續下去而不採取緩解措施,您可能很快就會看到「記憶體不足」警告。是時候關閉一些應用程式了。我將從您的瀏覽器視窗開始。
你認為這是一件好事嗎?頁面檔案擴充是邪惡的! !
不,不是。看,作業系統並沒有真正「擴展」現有檔案。它只是分配一個新的範圍。其效果與任何其他非連續檔案非常相似。舊的頁面文件內容保留在原處;它們不必複製到新的地方或類似的地方。由於與頁面檔案大小相比,大多數頁面檔案IO 都是相對較小的區塊,因此任何給定傳輸跨越範圍邊界的機會實際上非常罕見,因此碎片不會造成太大影響,除非碎片確實過多。
最後,一旦在擴展中“提交”空間的所有進程都退出(在操作系統關閉時,如果不是更早的話),範圍將被靜默釋放,並且頁面文件將恢復到其以前的大小和分配- 如果它之前是連續的,則它又是這樣。
因此,允許頁面文件擴充功能充當了一個完全免費的安全網:如果您允許它但係統從不需要它,系統將不會像人們經常聲稱的那樣“不斷地擴展和收縮頁面文件”,因此它將花費沒有什麼。如果您確實需要它,它將避免應用程式因“虛擬記憶體不足”錯誤而崩潰。
但是但是但是...
我在許多網站上讀到,如果允許頁面文件擴展,Windows 將不斷擴展和收縮頁面文件,這將導致頁面文件碎片,直到您對其進行碎片整理。
他們只是錯了。
如果您從未見過「記憶體不足」(或者,在舊版本中,「虛擬記憶體不足」)彈出窗口,則作業系統從未擴展過您的頁面檔案。
如果您確實看到該彈出窗口,則表示您的初始頁面檔案大小太小。 (我喜歡將其設定為觀察到的最大使用量的大約4 倍;即「%pagefile 使用峰值」perfmon 計數器應低於25%。原因:頁面檔案空間的管理方式與任何其他堆一樣,並且在有在大量可用空間的情況下效果最佳來玩。
但他們為什麼不只...
有人可能會爭辯說,作業系統應該讓分配發生,然後讓參考如果沒有可用的 RAM 來解決頁面錯誤,則會失敗。換句話說,在上面我們描述了初始頁面錯誤是如何運作的,如果「分配可用的 RAM 實體頁面」(步驟 1)因為沒有可用的而無法完成,該怎麼辦?和沒有地方可以將任何內容分頁以供使用嗎?
那麼尋呼機將無法解決頁面錯誤。它必須允許將異常(頁面錯誤)報告回錯誤線程,可能會更改為其他一些異常代碼。
設計理念是,如果超出提交限制,VirtualAlloc 將返回零(技術上是 NULL 指標)而不是地址,並且期望程式設計師知道 VirtualAlloc 呼叫可能會失敗是完全合理的。因此,程式設計師應該檢查這種情況並做一些合理的回應(例如給你一個機會保存到目前為止的工作,然後「優雅地」結束程式)。 (程式設計師:你確實檢查了從 malloc、new 等返回的 NULL 指針,是嗎?那麼為什麼不這樣做呢?)
但程式設計師不應該期望像這樣的簡單記憶體引用
i = 0; // initialize loop counter
可能會失敗 - 如果它位於成功提交的地址空間區域中則不會。 (或映射的位址空間,就此而言。)但是,如果遵循「允許過度分配分配,讓記憶體引用失敗」的理念,就會發生這種情況。
不幸的是,像上面程式碼行中的那樣的記憶體引用沒有一種傳回錯誤狀態的便捷方法!他們只是應該工作,就像加法和減法一樣。報告此類故障的唯一方法是將其視為例外。因此,為了處理它們,程式設計師必須將整個程序包裝在異常處理程序中。 (試試...捕捉等等。)
這是可以做到的......但是處理程序很難知道如何「做正確的事情」來回應這些異常,因為程式碼中可能會出現很多很多點。 (具體來說,它們可能出現在每一個對 VirtualAlloc'd 記憶體的記憶體引用,對使用 malloc 或 new 分配的記憶體的記憶體引用...以及對所有局部變數的記憶體引用,因為堆疊也是 VirtualAlloc'd 的。
簡而言之,在這些情況下讓程式優雅地失敗將是非常困難的。
另一方面,檢查從 VirtualAlloc (或 malloc 或 new,就此而言,儘管它們不完全相同)返回的 NULL 指標非常容易,然後做一些合理的事情......例如不嘗試去並執行程式需要該虛擬空間執行的任何操作。也許可以詢問用戶是否想要保存到目前為止的工作(如果有的話)。 (當然,太多的應用程式甚至懶得做那麼多事情。)
提交的其他用戶
順便說一句,「提交限制」不會因作業系統的各種分配(例如分頁和非分頁池、PFN 清單等)而減少;這些只是在發生時承擔責任。提交費用或提交限制也不受視訊 RAM 甚至視訊 RAM「視窗」大小的影響。
自己測試一下
您可以使用 SysInternals 網站上的 testlimit 工具來示範所有這些內容。選項 -m 將分配已提交的位址空間,但不會「觸及」它,因此不會導致 RAM 的分配。而選項 -d 將分配並引用頁面,導致提交費用增加和可用 RAM 減少。
參考
Windows 內部架構作者:魯西諾維奇、所羅門和約內斯庫。甚至還有演示可以讓您使用 testlimit 工具證明所有這些點。不過,我必須警告你,如果你認為很長,請注意:光是Mm這一章就有200頁;上面是一個極為簡化的版本。 (另請瀏覽簡介中的「致謝」部分。)
也可以看看MSDN VirtualAlloc 文檔
答案2
也許加起來出色的接受答案:
Windows 和大多數程式假設它們可以根據需要提交盡可能多的(虛擬)記憶體。這是不應停用頁面文件的重要原因之一,請參閱建議事實2.2在我的超級用戶問題。
我還連結到這個精彩的伺服器錯誤答案那裡清楚地表明了頁面文件的工作原理:
許多人似乎認為 Windows 會根據需要將資料推送到頁面檔案中。 EG:有些東西需要大量內存,但沒有足夠的 RAM 來滿足需要,因此 Windows 在最後一刻開始瘋狂地將資料從 RAM 寫入磁碟,以便為新的需求釋放 RAM。
這是不正確的。幕後還有更多事情發生。一般來說,Windows維護一個後備存儲,這意味著它希望看到記憶體中的所有內容以及磁碟上的某個位置。現在,當出現某些情況並需要大量記憶體時,Windows 可以非常快速地清除 RAM,因為該資料是已經在磁碟上,如果需要的話可以分頁回 RAM。因此可以說,頁面文件中的大部分內容也在 RAM 中;數據是先發制人地放置在頁面檔案中以加速新的記憶體分配需求。
進一步閱讀提供這裡