CefSharp Offscreen浏览器BitmapBuffer内存无法释放问题
CefSharp Offscreen模式ChromiumWebBrowser实例BitmapBuffer内存泄漏问题
问题现象
- 后台批量创建Offscreen模式的
ChromiumWebBrowser实例执行任务,按预期逻辑关闭并释放实例后,每创建一个实例会残留约4MB名为BitmapBuffer的内存占用,该部分内存始终无法被GC回收。 - 初始测试创建10个实例时内存占用约80MB,调整创建量到150个后内存占用达800MB,多次等待10-20分钟观测内存无自动释放,手动调用
GC.Collect()也无改善。
复现代码
public static int Main(string[] args) { CefSharpSettings.SubprocessExitIfParentProcessClosed = true; CefSharpSettings.WcfEnabled = false; var settings = new CefSettings() { //默认CefSharp使用内存缓存,指定缓存目录可持久化数据 CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache"), }; settings.CefCommandLineArgs.Add("disable-gpu-compositing", string.Empty); Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null); for (int i = 0; i < 150; i++) { Thread.Sleep(1000); Task.Run(CreateAndDispose); } //手动调用GC.Collect()无任何效果 Console.ReadKey(); return 0; } public static async Task CreateAndDispose() { var browser = new ChromiumWebBrowser("https://www.google.com/"); browser.GetBrowser().CloseBrowser(true); browser.RenderHandler = null; browser.Dispose(); browser = null; }
内存观测截图
问题原因
- 释放时序错误:创建
ChromiumWebBrowser实例后立即调用关闭和释放方法时,浏览器底层渲染进程还未完成初始化,CloseBrowser调用不会生效,底层持有的BitmapBuffer资源不会进入释放逻辑。 - 缺少生命周期等待:Offscreen模式的浏览器初始化、页面加载、关闭都是异步过程,直接同步调用Dispose不会等待渲染进程完成资源清理,会导致非托管位图缓冲区残留。
- RenderHandler资源未手动清理:默认
RenderHandler持有共享内存的位图引用,仅把RenderHandler属性置空不会触发其内部非托管资源释放。
正确释放方案
核心操作要求
- 必须等待
BrowserInitialized事件触发、IsBrowserInitialized属性为true后,再执行关闭逻辑,禁止创建实例后立刻释放。 - 调用
CloseBrowser后要等待BrowserClosed事件触发,确认底层资源释放完成后再清理托管引用。 - 浏览器关闭后主动调用RenderHandler的Dispose方法,不要仅将属性置空。
- 不要无限制并发创建Offscreen浏览器实例,建议使用对象池复用实例,从根源减少频繁创建销毁的内存开销。
修正后的CreateAndDispose实现
public static async Task CreateAndDispose() { var browser = new ChromiumWebBrowser("https://www.google.com/"); try { // 等待浏览器初始化完成 var initTcs = new TaskCompletionSource<bool>(); EventHandler initHandler = null; initHandler = (s, e) => { browser.BrowserInitialized -= initHandler; initTcs.TrySetResult(true); }; browser.BrowserInitialized += initHandler; using var initCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); initCts.Token.Register(() => initTcs.TrySetResult(false)); await initTcs.Task; // 等待浏览器关闭完成 var closeTcs = new TaskCompletionSource<bool>(); EventHandler<BrowserClosedEventArgs> closeHandler = null; closeHandler = (s, e) => { browser.BrowserClosed -= closeHandler; closeTcs.TrySetResult(true); }; browser.BrowserClosed += closeHandler; // 执行关闭 browser.GetBrowser().CloseBrowser(true); using var closeCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); closeCts.Token.Register(() => closeTcs.TrySetResult(false)); await closeTcs.Task; } finally { // 主动释放RenderHandler browser.RenderHandler?.Dispose(); browser.RenderHandler = null; // 释放浏览器实例 if (!browser.IsDisposed) { browser.Dispose(); } browser = null; } }
优化配置项
Cef初始化时可添加以下参数减少离屏渲染内存占用:
// 禁用离屏渲染共享位图缓存 settings.CefCommandLineArgs.Add("disable-bitmap-sharing", "1"); // 限制渲染进程数量,空闲时自动回收内存 settings.CefCommandLineArgs.Add("renderer-process-limit", "2");
内容的提问来源于stack exchange,提问作者Crazy
相关产品推荐
相关产品推荐

