浏览器自带的渲染进程合并策略

背景

Chromium 采用多进程架构,主要组件包括:浏览器进程 (Browser Process)、GPU 进程、渲染进程 (Renderer Process)、网络进程 (Network Process) 等。本方案主要关注渲染进程,因为页面js解析默认在渲染进程的主线程中。

目前每一个 Tab 标签打开同一网站都对应一个独立的 Render 进程。这种机制导致了应用后台经常驻留几十个进程,占用了大量系统资源,给人带来了不好的体验。

Chromium 自身包含多种渲染进程策略,会根据特定规则进行进程合并。因此,页面与进程的对应关系往往并不直观:哪些页面被合并在同一个进程,哪些页面是独立的进程,取决于具体的策略配置。

核心概念

在了解核心概念之前,我们先来看看chrome中创建渲染进程的默认策略,下面打开的网页都是相同地址的(同一个site):

  • 现象一:

通过 "+" 打开一个新网页不会创建新的渲染进程,这个主要是因为两个网页之间有opener关系(通过js可以实现两个页面之间相互操作),并且属于同一BrowserInstance。

  • 现象二:

通过超链接打开网页,此时不设置rel属性,默认是"noopener",会创建新的渲染进程。这是由于两个页面不属于同一个BrowserInstance了。

xml 复制代码
<!doctype html><meta charset="utf-8">
<a href="https://cursor.com/cn/download" target="_blank">open cursor download</a>
  • 现象三:

通过超链接打开网页,设置rel属性为"opener",此时页面都在同一个BrowserInstance,新的网页会复用之前渲染进程,

xml 复制代码
<!doctype html><meta charset="utf-8">
<a href="https://cursor.om/cn/download" target="_blank" rel="opener">open cursor download</a>

站点 (Site)

  • 定义: 站点(Site)是指具有相同注册域名 (eTLD+1)和 协议(scheme) 的 URL 集合。
  • 示例:
bash 复制代码
https://mail.google.com 和 https://docs.google.com 属于同一个站点 (https://google.com)
http://example.com 和 https://example.com 属于不同站点(协议不同)
https://a.example.com 和 https://b.example.com 属于同一个站点 (https://example.com)

/* 注:与同源的区别
同源:要求协议、域名(包括子域名)、端口完全相同
同站:只要求协议和 eTLD+1 相同,子域名和端口可以不同
*/
https://a.example.com:443/x 和 https://a.example.com:443/y 属于同源
  • 计算方法:
php 复制代码
// content/browser/site_info.cc
// static
GURL SiteInfo::GetSiteForOrigin(const url::Origin& origin) {
  // 取 eTLD+1
  std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
      origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
  // 返回 scheme + eTLD+1
  // 例如: https://mail.google.com -> https://google.com
  return SchemeAndHostToSite(origin.scheme(),
                             domain.empty() ? origin.host() : domain);
}

浏览实例 (BrowsingInstance)

  • 定义: 代表一组可以通过脚本相互访问的标签页和框架的集合(比如 window.open 打开的新窗口、同一页面里的 iframe)。
  • 关键特性:
    • 同一个 BrowsingInstance 内的页面可以通过 JavaScript 相互访问(前提是符合同源策略)
    • 每个 BrowsingInstance 拥有独立的 ID (BrowsingInstanceId)
    • BrowsingInstance 包含多个 SiteInstance
  • 创建时机:
    1. 使用 window.open() 打开新窗口时(带 noopener 则创建新 BrowsingInstance)
    2. 导航到需要 COOP (Cross-Origin-Opener-Policy) 隔离的页面时
    3. 使用 <a target="_blank"> 链接打开新页面时(取决于是否有 rel="noopener",默认为noopener"

站点实例 (SiteInstance)

  • 定义: 同一 BrowsingInstance 内、同一站点通常只对应一个 SiteInstance。同一 SiteInstance 内的文档共享同一个渲染进程。
  • 关键特性:
    • 每个 SiteInstance 关联一个 SiteInfo(包含站点 URL、进程锁定信息等)
    • 每个 SiteInstance 属于一个 BrowsingInstance
    • 同一 SiteInstance 的所有文档必须在同一个进程中运行
    • 一个 BrowsingInstance 中,每个站点最多只有一个 SiteInstance(正常情况下)

关系展示

📌默认情况下,同一BrowsingInstance下,同一site通常复用同一个同一SiteInstance,运行在同一渲染进程,不同BrowsingInstance下,同一site会被保存到不同SiteInstance,大多运行在不同渲染进程

进程模型

Chromium 支持四种进程模式,通过命令行参数 --process-per-site-instance--process-per-site--process-per-tab--single-process 可以切换。

Process-per-site-instance (默认模式)

  • 策略: 同一个 SiteInstance 使用一个进程。
  • 特点:
    • Chrome 默认使用的模式
    • 兼顾性能与安全性的中庸方案
    • 同一 BrowsingInstance 内的同一站点共享进程
    • 不同 BrowsingInstance 的同一站点可能使用不同进程(也可能复用)
  • 源码体现:
scss 复制代码
// content/browser/browsing_instance.cc
scoped_refptr<SiteInstanceImpl> BrowsingInstance::GetSiteInstanceForURL(
    const UrlInfo& url_info,
    bool allow_default_instance) {
  SiteInfo site_info = ComputeSiteInfoForURL(url_info);
  
  // 检查是否已存在该站点的 SiteInstance
  auto it = site_instance_map_.find(site_info);
  if (it != site_instance_map_.end()) {
    return it->second;  // 复用现有 SiteInstance(进程)
  }
  
  // 创建新的 SiteInstance
  // ...
}

Process-per-site

  • 策略: 同一个 site 使用一个进程,跨越所有 BrowsingInstance。
  • 特点:
    • 整个浏览器进程中,同一站点只有一个渲染进程
    • 更激进的进程共享,内存占用更低
    • 安全隔离性降低(渲染进程卡死,所有窗口白屏)

源码体现:

rust 复制代码
// content/browser/site_info.cc
bool SiteInfo::ShouldUseProcessPerSite(BrowserContext* browser_context) const {
  // 检查是否为需要 process-per-site 的站点
  return GetContentClient()->browser()->ShouldUseProcessPerSite(
      browser_context, site_url_);
}

// 进程复用策略枚举:
// content/browser/process_reuse_policy.h
enum class ProcessReusePolicy {
  PROCESS_PER_SITE,  // 整个浏览器共享进程
  // ...
};

Process-per-tab

  • 策略: 每个标签页使用一个独立进程。
  • 特点:
    • 每个标签页独立进程,即使是同一站点
    • 隔离性最强,但内存和进程数开销最大
    • 不考虑站点的概念
  • 使用场景:
    • 测试和调试
    • 需要极强隔离性的场景

3.4 Single Process

  • 策略: 所有标签页共用一个渲染进程。
  • 特点:
    • 主要用于调试
    • 性能开销最小,但没有安全隔离
    • 生产环境不推荐使用

补充说明:

    • --renderer-process-limit=N :限制渲染器进程的最大数量为 N

默认情况下,64位机器:max_count≈物理内存➗(2✖85)

相关推荐
longze_71 天前
google A2UI Windows 源码
ui·google·a2ui·front end
nvd112 天前
创建自己的云开发环境-GCP Cloud Workstations 配置指南
google·googlecloud
ArkAPI3 天前
腾讯AI基础设施的系统论:从推理框架的算子融合到智能体的任务分解
人工智能·ai·google·aigc·腾讯·多模态处理·arkapi
GPTMirrors镜像系统6 天前
谷歌Gemini"Something went wrong"错误解决方法:2步快速解除限制(2025最新教程)
google·gemini
后端小肥肠8 天前
谷歌Opal + Gemini 3 Pro 强强合体:手搓“AI漫剧生成器”只需 5 分钟!
google·aigc·gemini
坐吃山猪8 天前
A2UI快速入门
google·llm·a2ui
草帽lufei12 天前
用 Gemini3 Flash 做了多半天开发,我离下岗又近了一步
google·ai编程·gemini
感谢地心引力12 天前
【AI】免费的代价?Google AI Studio 使用指南与 Cherry Studio + MCP 实战教程
人工智能·ai·google·chatgpt·gemini·mcp·cherry studio
北极的树18 天前
Google ADK上下文工程:当AI Agent学会像编译器一样管理上下文
google·agent