Chromium was designed from the very start as a multiprocess browser. Most people think it has one process for each tab and while that is somewhat close to the truth, the real picture is a bit more complicated. It supports a few different modes of operation which differ in how web pages are assigned to processes. Those are called “process models”. It is highly recommended to read the previous posts introducing some basic concepts used by Chromium, which I will use to explain how the different process models work.
Chromium uses the operating system process as a unit of isolation. It uses Blink to render web documents, which it runs in restricted renderer processes. The sandbox does not allow any renderer processes to communicate between each other and the only way to achieve that is to use the browser process as an intermediary. This design allows us to isolate web pages from each other and potentially have a different level of privileges for each process.
Before delving into the actual models the browser supports, there are couple of more bits of detail to cover - cross-process navigation and SiteInstance caveats.
A tab in the browser UI gets a visual representation of the web page from the renderer process and draws it as its content. When navigating from one page to another, the browser makes a network request and gives the response to Blink for rendering. Often, the same instance of the rendering engine, running in the same process, is used. However, in many cases, navigations can result in a new renderer process being created and a brand new instance of Blink being instantiated. The response is handed off to the new renderer process and the tab is then associated with the new process.
The ability to perform cross-process navigations is a core part of Chromium’s design. It incurs the cost of starting a new process, however it also improves performance, as using a new process has a clear memory space, free of fragmentation. Abandoning the old process can be quick (process kill) and also helps mitigate memory leaks, as that process exits and its memory is released back to the operating system. Most importantly, though, changing processes under the hood is a key building block of the security model.
Chromium’s security model also allows for different privilege levels for content being rendered. In general any content coming from the web is considered lowest privilege level. Chromium internal pages, such as chrome://settings, require more privileges, as they need to read or modify settings or data available only in the browser process. The security model does not allow pages from different privilege levels to use the same process, so a cross-process navigation is enforced when crossing privilege level.
Previous posts in this series described SiteInstance and said that in the example setup, all of a.com, b.com, c.com, d.com were SiteInstances. This is the ideal model to use and is the goal of the “Site Isolation” project, but currently Chromium does not reflect this in reality. Here is a list of caveats that apply to the default Chromium configuration at the time of this post:
SiteInstance is assigned only to the top-level frame by default. Subframes share the same one as the main frame.
SiteInstance does not always reflect the URL of the current document. Once the SiteInstance URL is set, it doesn’t change, even though the frame can navigate across many different Sites. However, SiteInstance can change when navigating cross-site.
Chromium avoids process swaps on cross-site renderer-initiated navigations (e.g. link clicks) because those would be likely to break script calls on windows that expect to communicate with each other (and thus break compatibility with the web). In contrast, it tends to use process swaps on cross-site browser-initiated navigations (e.g. typing URL in the omnibox) because the user is making an effort to leave the site, so it’s not as bad to break the script calls.
To help illustrate the difference between the different process models, I have included screenshots of the Chromium Task Manager showing the processes and what URLs they are rendering. The setup I have used is the following:
Tab navigated to http://tests.netsekure.org/main-b-c.html. The main document includes two iframes - one to https://google.com and one to https://github.com. It also contains a button that opens a new tab through window.open() call. It causes the new tab to be in the same BrowsingInstance as the tab that opened it.
Newly opened tab from the initial tab, which is navigated to http://tests.netsekure.com/main-sub.c.html. Notice that it is different top level domain from the initial tab (.org vs .com). It includes an iframe to https://pages.github.com.
User opened tab navigated to http://tests.netsekure.com/empty.html
User opened tab navigated to http://tests.netsekure.com/to_slow.html
At the time of this post, the current set of process models is:
Process per tab
Process per Site
Process per Site instance (default)
Site per process (experimental)
This is a mode in which Chromium does not use multiple processes. Rather, it combines all of its parts into a single process. It is also a mode in which there is no sandboxing, as the browser needs access to both the network and the filesystem. It exists mainly for testing and it should never be used!
Process per tab
This process model is the simplest one to understand and is what most people intuitively think is the mode of operation of the browser. Each tab gets a dedicated sandboxed process that runs the Blink rendering engine. Navigations do not usually change processes. Note however that since the security model does not allow for content with different privileges to live in the same process, it does actually change processes on privilege change. An example would be navigation from https://dev.chromium.org to chrome://settings.
Process per Site
In this process model, each Site gets mapped to a single process. When multiple tabs are navigated to the same Site, they will all share the same process. Navigations can change processes.
It is not the default model, since running multiple tabs with heavy web pages, such as Google Docs, leads to low performance - too much contention on the main thread, memory fragmentation, etc.
Process per Site instance
This is the default process model for Chromium. Each SiteInstance is mapped to a process by default. Multiple tabs navigated to the same Site end up in separate SiteInstances, therefore they reside in separate processes. Navigations also can change processes. All the SiteInstance caveats apply and not the idealized version of SiteInstance.
Site per process
This is an experimental process model for developing the “Site Isolation” project. It comes closer to the desired design for Chromium, where there is a SiteInstance for each frame. Additionally, it is using the idealized definition of SiteInstance, where only URLs from the same SiteInstance can be loaded in the same process. Navigations can change processes in any frame on a page, whereas all other process models support changing processes only on the top frame.
I hope these posts have helped demystify a bit how the Chromium makes decisions on which process to use for specific tab and URL. If there are other clarifications I can make, feel free to ping me over on Twitter and I would be happy to.