Sql-Server

SQL Server 使用的 RAM 超出了應有的範圍

  • January 7, 2022

我有一個使用更多 RAM 的 SQL Server 2012 實例。

SQL Server 程序使用大約 22.5GB RAM:

任務管理器

實例配置為使用最大 10GB:

SSMS 記憶體屬性

這比預期的要多。(這將導致伺服器崩潰,我們必須重新啟動才能將其恢復)。

我用這個查詢檢查了記憶體使用情況(職員):

select type, name, pages_kb/1024.0/1024.0 "size Gb" from sys.dm_os_memory_clerks
order by pages_kb desc 

SQL Server 似乎只看到大約 7GB RAM 被使用:

查詢結果

我知道這是 SQL Server 的舊版本(遺憾的是它沒有修補到最新版本),但我找不到任何關於 SQL Server 2012 SP2 中記憶體洩漏的明確文件。

我應該在哪裡查找 SQL Server 使用大約 200% 的原因?

此實例上有一個連結伺服器。很多使用 SQL 驅動程序(SQLNCLI 和 SQLNCLI11),但也有一些使用“用於 HFSQL 的 PC SOFT OLE DB 提供程序”,這是我以前從未見過的。

有什麼辦法可以“證明”這個驅動程序是問題所在?客戶端可能不會同意基於假設更改設置,因此如果有任何方法(除了禁用)來清楚地顯示連結伺服器正在使用多少 RAM,那將是無價的。

@Aleksey:這就是產品的回報 在此處輸入圖像描述

dm_os_memory_clerks 沒有顯示記憶體的事實強烈表明記憶體是在 SQL Server 引擎之外分配的。

“用於 HFSQL 的 PC SOFT OLE DB 提供程序”

那將是罪魁禍首。許多第 3 方 OleDb 提供程序未經過強化以用於長期流程。桌面應用程序中的小記憶體洩漏甚至很少引起注意,因此他們通過測試而沒有發現問題。

此處最好的解決方案是將 OleDB 驅動程序移至 SSIS 包或 PowerShell 作業或類似的短期程序。如果這是不可能的,您可以嘗試在仍然使用連結伺服器的同時將 OleDb 提供程序推送到程序外,或者清除“允許程序內”標誌並進行一系列 DCOM 配置(參見例如設置連結伺服器與-process OLEDB 提供程序),或使用SSIS 數據流傳輸目標並將連結伺服器替換為

SELECT * FROM OPENQUERY([Default Linked Server for Integration Services], N'Folder=Power BI;Project=SSISPackagePublishing;Package=Package.dtsx')  
 

一種解決方案是按計劃反彈 SQL Server。

有什麼辦法可以“證明”這個驅動程序是問題所在?

沒有任何東西可以跟踪 SQL Server 控制之外的本機程式碼記憶體分配。我想證明它的唯一方法是反复訪問連結伺服器,看看是否可以觸發記憶體洩漏。

如果您將支持案例升級到足夠多的程度,他們可能會最終找到洩漏。

擴展我最初對大衛的回答留下的評論:

幾個關鍵點。首先,並非所有記憶體對象和代理都出現在 DMV 中,因此從技術上講,它SQL Server 分配的。其次,您要做的是收集用於記憶體分配的 xperf/wpr,然後通過 AIFO(在內部分配,在外部釋放)以及峰值切割數據。這應該為您提供實際分配虛擬記憶體的模組和呼叫堆棧。第三,可以通過 GFLAG 開啟堆跟踪,但這通常不如 xperf/wpr 提供那麼好的結果。

雖然它不會給出直接的答案,但它應該是如何獲取數據以找出問題根源的指南(儘管這可能與根本原因不同)。

我寫了一個小repro來模擬你的情況……

  1. 我將最大伺服器記憶體設置得非常低(無論如何它是一個小型 VM),執行緒數非常低,並確保它在記憶體中沒有任何內容。請記住,執行緒堆棧、模組等計入最大伺服器記憶體,因此使用完整的緩衝池,您將始終顯示高於最大伺服器記憶體值。

最大伺服器記憶體設置為 512 MB

SQL Server 程序的虛擬記憶體分配 2. 我創建了一個快速複製,它會佔用大量記憶體。現在,我正在做一些 OP 缺少的事情,因為我正在查看記憶體分配的類型(儘管它們最終都會通過虛擬分配

$$ except some physicalpages calls which I’m not using here $$) 這樣我就可以知道正在進行哪種類型的分配,這有助於排除故障。 現在我們有更多的記憶體使用(從 470 MB 到 2.5 GB): SQL Server 現在使用更多記憶體

由於這是一個微不足道的重現,我在記憶體使用之前、期間和之後設置了 ETW 擷取和擷取時間。根據記憶體分配發生的速度,無論需要 1 天、1 小時還是 1 個月,您收集數據的設置可能會發生變化。 3. 我可以看到這是專門分配的堆數據,它排除了 SQL Server 內部的許多不同項目(儘管堆仍然用於各種項目),它確實有助於查找位置。

由於我專門配置了 ETW 擷取以獲取記憶體分配(VirtualAlloc、HeapAlloc 等),因此它可用於檢查所謂的 Allocated Inside Freed Outside 或 AIFO 記憶體,這意味著記憶體在擷取期間分配並繼續存在在擷取結束之後。如果我使用堆棧、送出類型、符號等項目設置我的環境,則可以查看大部分記憶體正在使用的位置。下面是一個按送出類型 (AIFO) 和堆棧劃分的範例。請注意,發生這種情況的方式有很多種,因此可能會導致 1,000 個分配死亡,或者是一個巨大的分配,可能介於兩者之間。

ETW 數據

您會注意到對於標記 #1,有一個 2 GB 的未分配分配(它一直存在)。標記 #2 顯示了創建它的堆棧。我想提請您注意仍然是 PID 756 並且仍然是 SQL Server 的程序,但是您會看到,通過使用公共符號,有這個 2 GB 分配的堆棧,它顯示了對它的RtlpAllocateHeapInternal呼叫顧名思義,在堆上分配空間(在本例中為預設程序堆),這與我們上面螢幕截圖中的數據一致,該螢幕截圖顯示了正在分配的堆數據。如果我們查看 ETW 數據中的堆棧,它表明這是通過呼叫CSSDet.dll的模組分配的,該模組在 Microsoft Public Symbols Server 上沒有任何符號,這表明這不是 Microsoft 產品。

同樣,這是一個簡單的重現,我編寫了 DLL,但是如果在實際環境中是這種情況,下一步將是檢查 DLL 製造商並聯繫他們,另外你還需要呼叫堆棧分配,他們可以使用它來幫助追踪程式碼中的問題。


您能否添加一些有關 ETW 設置的詳細資訊以擷取和分析此數據?

OP 執行此操作的最簡單方法是 wpr 擷取內置配置文件(儘管它確實收集了更多數據,但這使得它更容易)。wpr -start VirtualAllocation

$$ … $$你是如何讓你的自定義 .dll 載入和執行的$$ .. $$

我使用了典型的防病毒/惡意軟體路線,並為使用者模式程序編寫了自己的模組注入器。我沒有為此特定目的編寫它,但它適用於快速複製。請注意,我還從 EKM 模組中調試了很多記憶體洩漏,這是 3rd 方提供程序的另一個常見模組載入點。

引用自:https://dba.stackexchange.com/questions/305473