最近工作遇到一個問題:
從 tab 1 切到 tab 2 時,tab 1 的部分界面被疊加到了 tab 2 上,過幾秒才消失。這類問題表面看像是瀏覽器卡頓,其根因卻可能出現在三層不同的系統裏:應用層 Chrome 的渲染管線、操作系統的桌面合成與顯示疊加路徑、以及顯示設備本身的臨時殘影。弄清楚像素是怎樣從網頁一路流到屏幕,才能對症下藥。
下文分三塊來講:Chrome 如何把像素畫出來、為什麼會出現跨標籤的殘影、如何一步步定位與解決。同時給一段可直接保存為 html 的小實驗代碼,用來複現與診斷有沒有頁面重繪被延遲的問題。
一、Chrome 到底怎樣把一個標籤頁畫到屏幕上
Chrome 的現代渲染架構叫 RenderingNG。簡化地説,一個標籤頁在渲染時會經歷 Layout/Paint → Raster → Composite → Display 這條流水線。Blink 產出繪製命令,Skia 負責把繪製命令柵格化成位圖紋理,隨後由 Compositor 把各層 Layer/Quad 組合成合成幀,通過 GPU Process 提交到系統窗口的後緩衝區。Chrome 在 Windows 上普遍經由 ANGLE 層把 WebGL/Canvas 等調用映射到 D3D11、OpenGL 或 Vulkan,最後交給系統的桌面合成器顯示。官方文檔對這條管線有系統説明。(Chrome for Developers)
在 Windows,桌面最終由 DWM 合成。新一點的 Windows 10/11 和驅動會用到 MPO(Multi-Plane Overlay,多平面疊加)這套硬件路徑:顯卡顯示控制器直接把多個平面組合輸出,某些視頻或窗口能單獨成為一個平面,從而降低功耗或提升流暢度。微軟的驅動與 MPO 規範説明了這些疊加層的工作方式與硬件要求。(Microsoft Learn)
Chrome 還使用了 Window Occlusion(窗口遮擋感知)與標籤節流、丟棄等策略,以減少對被遮擋或後台標籤的活動消耗。這些策略在官方文章與開發文檔裏也有詳述:Chrome 會跟蹤窗口可見性事件,必要時才重新計算遮擋;當系統內存緊張時,後台標籤會被丟棄,回到標籤時再恢復。(Chromium Blog)
把這三點組合起來看:Chrome 生成合成幀 → 操作系統用 DWM/MPO 把幀疊加到屏幕 → 後台標籤可能被節流或丟棄。任何一個環節的異常,都可能表現為你看到的短暫殘影。
二、為什麼會出現 tab 1 的像素疊加在 tab 2 上
從大量用户案例與官方議題可以歸納出幾類高概率原因:
1)MPO 或圖形驅動的疊加平面問題 當 DWM 使用 MPO 進行多平面疊加時,如果顯卡驅動或合成器在平面複用、失效區域計算上有瑕疵,就可能把上一幀或上一窗口的內容短暫地保留在某個平面裏,肉眼就像是上一標籤的畫面“壓”在當前標籤上。社區與驅動論壇裏,MPO 導致的黑屏、閃爍、殘影在 Chromium 系應用裏有不少報告;很多人通過暫時禁用 MPO 規避了問題。微軟文檔解釋了 MPO 的機制,第三方技術帖給出如何通過註冊表切換 MPO 的方法(作為診斷手段)。(Microsoft Learn)
2)Window Occlusion / Tab 節流與後台 EcoQoS/Efficiency mode Windows 11 的 Efficiency mode 會給後台進程施加 EcoQoS,降低其調度優先級與頻率。Chrome 自身也會對後台標籤進行節流甚至丟棄。當你切回標籤時,如果渲染進程一時間搶不到足夠的 CPU/GPU 時隙,或者頁面需要恢復上下文,前台窗口可能先顯示了一幀舊畫面或空白,再過幾秒才更新。微軟的性能團隊文章解釋了 Efficiency mode/EcoQoS 對後台進程的影響;Chromium 的更新日誌與博客也介紹過標籤節流與遮擋計算帶來的變化。(Microsoft for Developers)
此外,Chrome 110 起自動丟棄後台標籤的策略在內存吃緊時更積極,切回來需要重建頁面狀態,這段時間內可能看到舊內容或白屏。(Ars Technica)
3)瀏覽器 Compositor 或 GPU 路徑上的個別缺陷 Chromium 的議題裏可以找到類似描述:切換標籤時合成器交換了一幀空白或舊幀、Canvas 內容在標籤切換後暫時丟失、窗口不總是重繪等。這類問題往往與特定版本、特定後端(D3D11/OpenGL/Vulkan)、特定硬件或系統主題有關,升級或切換後端可緩解。(Chromium Issues)
4)顯示器層面的臨時殘影 如果你在 Chrome 之外,比如切到純色桌面仍能看到淡淡的界面印記,可能是顯示面板的短時圖像殘留。廠商科普文章解釋了顯示器的 Ghosting 與 Image retention,這種現象一般是臨時性的,與瀏覽器無關,但會把診斷帶偏。可用同色全屏圖像做對照驗證。(HP)
5)擴展、實驗性 flag、硬件加速的視頻解碼組合問題 有用户在 Chrome 幫助社區與 SuperUser 上反饋,硬件加速與某些擴展、或視頻解碼疊加時會出現空白/殘影,關閉硬件加速或僅關閉硬件加速的視頻解碼能緩解。這説明並非純粹 CPU 卡頓,而是圖形路徑交互的副作用。(Super User)
三、一個可操作的診斷到修復的路徑
下面是一套面向 Windows 的排障流程;macOS/Linux 的要點放在章節末尾。為了避免“拍腦袋”,每一步都給出可驗證的客觀信號。
步驟 A:確認是否為顯示器殘影
在瀏覽器外,打開一個純色全屏窗口(比如 Win + Ctrl + C 打開色濾鏡或找張純色壁紙),觀察殘影是否仍在。如果仍在,優先檢查顯示器線纜、刷新率與響應時間設置,參考廠商的 Ghosting 處理建議。(HP)
步驟 B:看 Chrome 的圖形狀態
在地址欄輸入 chrome://gpu,確認 Graphics Feature Status 是否普遍為 Hardware accelerated,下方 Problems Detected 是否有報錯;這能幫助你判斷問題在硬件加速路徑還是軟件柵格路徑。(Super User) Shift + Esc 打開 Chrome 內置任務管理器,確認是否存在 GPU Process 且在切換標籤的一瞬有活動。(Super User)
步驟 C:排除擴展與配置干擾
新建一個臨時用户資料或用隱身窗口、禁用全部擴展試試是否復現。許多詭異疊影最終是擴展或腳本注入造成的。(Tom’s Guide Forum)
步驟 D:驗證 Windows Efficiency mode / EcoQoS 影響
打開 任務管理器,在 進程 列表展開 Chrome,看 狀態 列是否標註 效率模式。若發現前台切換時 Chrome 仍落在效率模式裏,可以暫時在任務管理器對 chrome.exe 右鍵關閉效率模式,再觀察是否改善。(TLDCRM - Total Lead Domination) 也可在快捷方式 Target 末尾添加參數 --disable-features=UseEcoQoSForBackgroundProcess 做臨時驗證,減少後台進程因 EcoQoS 被過度限制的情況。相關討論見 Microsoft Q&A。(Microsoft Learn) 理解 效率模式 的本意與機制,微軟性能團隊文章與 Edge 官方頁有説明,便於權衡是否長期關閉。(Microsoft for Developers)
步驟 E:驗證 MPO 是否觸發了疊加異常(高級)
如果你的現象高度像是上一標籤的畫面“壓”在當前標籤上,並且伴隨視頻播放區域更明顯的錯層,極可能與 MPO 疊加平面複用有關。作為診斷可以短期關閉 MPO:
以管理員打開 CMD/PowerShell,執行: reg add HKLM\SOFTWARE\Microsoft\Windows\Dwm /v OverlayTestMode /t REG_DWORD /d 5 /f 重啓後觀察是否徹底沒有殘影。恢復時將該值刪除或設為 0。此法廣見於技術社區帖,微軟官方文檔只介紹了 MPO 的工作原理與硬件要求,請將其視為臨時診斷手段,不作為默認長期配置。(xahertz.com) 如果關閉 MPO 後殘影立刻消失,優先路線是更新顯卡驅動與系統補丁,再恢復 MPO 以獲得更低功耗與更好的視頻疊加路徑。
步驟 F:切換 ANGLE 後端或暫時關閉硬件加速做 A/B 驗證
Chrome 在 Windows 默認通過 ANGLE 的 D3D11 後端工作。你可以在 chrome://flags 裏找到 Choose ANGLE graphics backend,切到 OpenGL 或 D3D11,重新啓動瀏覽器看現象是否改變;這能幫助判斷問題是否與某條圖形後端路徑耦合。ANGLE 與該 flag 的官方描述可參考下述文檔。(Chromium Git Repositories)
還可以在 設置 → 系統與性能 裏臨時關閉 使用可用的硬件加速,如果殘影消失,説明問題確實落在硬件加速路徑上,再回到前述 MPO/驅動/ANGLE 的組合去定位根因。社區與 SuperUser 有長期經驗貼佐證此思路。(Super User)
步驟 G:更新與重置
將 Chrome 升級到最新穩定版,很多合成器與遮擋計算問題都在版本更替裏被修復。 清理驅動並安裝顯卡最新 WHQL 版本,DWM 異常與 Dxgmms2.sys 視頻內存管理等問題在系統更新裏也常見修復條目。(Microsoft Support) 重置 Chrome 設置,或新建乾淨用户數據目錄複測。 檢查是否啓用了 HDR、G-Sync/FreeSync、高分辨率外接屏幕的多刷新率混用,這些都可能改變 MPO 與合成策略(多顯示器不同刷新率時疊加層更復雜)。相關技術帖表明在多顯場景下問題更易出現。(Microsoft Learn)
步驟 H:理解標籤丟棄與白屏的預期表現
當系統內存緊張或後台時間過長,Chrome 可能丟棄後台標籤,切回時需要重載頁面。此時出現短暫白屏是預期行為,而非殘影。Chrome 的官方博文對標籤丟棄有定義與用户體驗説明。(Chrome for Developers)
四、給你一個可運行的小實驗:測頁面重繪是否被延遲
很多人感覺是“殘影”,其實是標籤切回後短時間沒有新幀,DWM 繼續顯示上一幀或上一窗口的內容。下面這段 HTML 可以直接保存為 tab-repaint-diagnose.html,用兩個標籤分別打開它與任意網頁,多次在兩者之間切換;它會:
以 requestAnimationFrame 驅動一個時鐘畫布,如果切回時 raf 間隔突然非常大,説明後台確有節流或恢復延遲; 監聽 visibilitychange 與 performance.now 跳變,輸出 logs; 故意繪製移動的條紋,肉眼判斷畫面是否瞬時停住不動。
<!doctype html>
<html lang='zh-CN'>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>Tab Repaint Diagnose</title>
<style>
html,body{margin:0;padding:0;background:#111;color:#eee;font-family:system-ui,Segoe UI,Roboto,Arial}
#wrap{display:flex;flex-direction:column;gap:12px;padding:16px}
#c{width:100%;height:280px;background:#000;border:1px solid #333}
#log{height:220px;overflow:auto;background:#0b0b0b;border:1px solid #333;padding:8px;font:12px/1.4 ui-monospace,Menlo,Consolas}
.hint{opacity:.8}
</style>
</head>
<body>
<div id='wrap'>
<canvas id='c'></canvas>
<div class='hint'>切換標籤來回觀察:若回到本頁後畫布一段時間不動,或者日誌裏出現很大的 raf 間隔,就説明存在節流或恢復延遲。</div>
<div id='log'></div>
</div>
<script>
(function(){
const cv = document.getElementById('c');
const ctx = cv.getContext('2d');
const log = document.getElementById('log');
let last = performance.now(), rafId = 0, t = 0;
function fit(){
const dpr = Math.max(1, Math.min(2, window.devicePixelRatio || 1));
cv.width = Math.floor(cv.clientWidth * dpr);
cv.height = Math.floor(cv.clientHeight * dpr);
ctx.setTransform(dpr,0,0,dpr,0,0);
}
window.addEventListener('resize', fit, {passive:true});
fit();
function wlog(msg){
const time = new Date().toLocaleTimeString();
const line = document.createElement('div');
line.textContent = `[${time}] ${msg}`;
log.appendChild(line);
log.scrollTop = log.scrollHeight;
}
document.addEventListener('visibilitychange', ()=>{
wlog(`visibility: ${document.visibilityState}`);
});
function draw(now){
const dt = now - last; last = now; t += dt * 0.001;
if (dt > 200){ // 超過 200ms 的間隔,懷疑有節流或恢復延遲
wlog(`raf gap ${Math.round(dt)} ms`);
}
// 背景
ctx.fillStyle = '#000';
ctx.fillRect(0,0,cv.clientWidth,cv.clientHeight);
// 移動條紋
for(let i=0;i<40;i++){
const y = (i*8 + (t*120)%160)|0;
ctx.fillStyle = i%2 ? '#2a9d8f' : '#264653';
ctx.fillRect(0,y,cv.clientWidth,6);
}
// 時鐘
ctx.fillStyle = '#e9c46a';
ctx.font = '24px ui-monospace, Menlo, Consolas';
ctx.fillText(`now=${now.toFixed(1)} dt=${dt.toFixed(1)} ms`, 12, 32);
rafId = requestAnimationFrame(draw);
}
rafId = requestAnimationFrame(draw);
wlog('started');
})();
</script>
</body>
</html>
若實驗顯示 raf 間隔經常在切回時出現幾百毫秒甚至數秒的跳變,再結合你前面的症狀,就能更確信問題並非顯示器殘影,而是瀏覽器或系統合成路徑在恢復時機上出現延遲或舊幀複用。
五、Windows/macOS/Linux 的差異化注意點
在 Windows MPO 與驅動的組合最常見:多顯示器、HDR、不同刷新率並存時,疊加策略更復雜,更容易觸發舊幀複用或閃爍。微軟文檔解釋了 MPO 的平面佔用與硬件要求;Chromium 也在推進對多個硬件疊加的更好利用。(Microsoft Learn) Window Occlusion 與節流策略是 Chrome 的既定優化,切換路徑上如果被 Efficiency mode 影響,恢復會慢半拍;參考微軟性能團隊關於 EcoQoS 的文章。(Microsoft for Developers) 在 macOS Chrome 通過 Core Animation 與 Metal 呈現。個別版本下會出現標籤切換後空白或舊幀的個案,多與 Core Animation 圖層與 Compositor 的交互相關。可以優先升級 macOS 與 Chrome,測試是否在全屏與非全屏之間差異明顯。社區裏有近期反饋。(Reddit) 若外接顯示器出現全局閃爍或輕微保留影像,要排除顯示設備與線材問題。(MacRumors Forums) 在 Linux 合成器與後端切換影響更大。Wayland/Xorg、picom 等合成器設置、Chrome 的 --use-gl=desktop、Vulkan 切換,對閃爍與菜單陰影異常很敏感。可嘗試禁用第三方合成器或切換渲染後端驗證。(GitHub)
六、把解決方案排成一張執行清單(由易到難)
升級 Chrome、系統補丁與顯卡驅動,複測是否消失。Dxgmms2 與合成器相關的穩定性修復會出現在系統更新裏。(Microsoft Support) 查看 chrome://gpu 與 Chrome 任務管理器,確認硬件加速與 GPU Process 正常;用隱身模式或新建用户資料排除擴展干擾。(Super User) 在任務管理器對 Chrome 關閉 效率模式,或用 --disable-features=UseEcoQoSForBackgroundProcess 做階段性驗證。(TLDCRM - Total Lead Domination) 在 chrome://flags 切換 Choose ANGLE graphics backend(例如改為 OpenGL 再試),或在設置裏臨時關閉硬件加速做對照。(Chromium Git Repositories) 若明顯像疊加層複用導致的舊幀透出,可按上文方法臨時禁用 MPO 驗證;驗證有效後再以驅動更新為主,恢復 MPO。(xahertz.com) 對於確實是標籤丟棄造成的白屏,考慮減少常駐標籤、增內存,或把特定標籤設為應用窗口,降低被丟棄概率。(Chrome for Developers)