OLD | NEW |
1 A zygote process is one that listens for spawn requests from a master process | 1 A zygote process is one that listens for spawn requests from a master process |
2 and forks itself in response. Generally they are used because forking a process | 2 and forks itself in response. Generally they are used because forking a process |
3 after some expensive setup has been performed can save time and share extra | 3 after some expensive setup has been performed can save time and share extra |
4 memory pages. | 4 memory pages. |
5 | 5 |
6 On Linux, for Chromium, this is not the point, and measurements suggest that the | 6 More specifically, on Linux, it allows to: |
7 time and memory savings are minimal or negative. | 7 * Amortize the runtime and memory cost of the dynamic loader's relocations, |
| 8 which is respectively ~6 MB and 60 ms/GHz per process. |
| 9 See [Appendix A](#appendix-a-runtime-impact-of-relocations) and |
| 10 [Appendix B](#appendix-b-memory-impact-of-relocations). |
| 11 * Amortize the runtime and memory cost for initializing common |
| 12 libraries, such as ICU, NSS, the V8 snapshot and anything else in |
| 13 `ContentMainRunnerImpl::Initialize()`. With the above, this saves |
| 14 up to ~8 MB per process. See [Appendix C](#appendix-c-overall-memory-impact). |
8 | 15 |
9 We use it because it's the only reasonable way to keep a reference to a binary | 16 Security-wise, the Zygote is responsible for setting up and bookkeeping the |
| 17 [namespace sandbox](linux_sandboxing.md). |
| 18 |
| 19 Furthermore it is the only reasonable way to keep a reference to a binary |
10 and a set of shared libraries that can be exec'ed. In the model used on Windows | 20 and a set of shared libraries that can be exec'ed. In the model used on Windows |
11 and Mac, renderers are exec'ed as needed from the chrome binary. However, if the | 21 and Mac, renderers are exec'ed as needed from the chrome binary. However, if the |
12 chrome binary, or any of its shared libraries are updated while Chrome is | 22 chrome binary, or any of its shared libraries are updated while Chrome is |
13 running, we'll end up exec'ing the wrong version. A version _x_ browser might be | 23 running, we'll end up exec'ing the wrong version. A version _x_ browser might be |
14 talking to a version _y_ renderer. Our IPC system does not support this (and | 24 talking to a version _y_ renderer. Our IPC system does not support this (and |
15 does not want to!). | 25 does not want to!). |
16 | 26 |
17 So we would like to keep a reference to a binary and its shared libraries and | 27 So we would like to keep a reference to a binary and its shared libraries and |
18 exec from these. However, unless we are going to write our own `ld.so`, there's | 28 exec from these. However, unless we are going to write our own `ld.so`, there's |
19 no way to do this. | 29 no way to do this. |
20 | 30 |
21 Instead, we exec the prototypical renderer at the beginning of the browser | 31 Instead, we exec the prototypical renderer at the beginning of the browser |
22 execution. When we need more renderers, we signal this prototypical process (the | 32 execution. When we need more renderers, we signal this prototypical process (the |
23 zygote) to fork itself. The zygote is always the correct version and, by | 33 zygote) to fork itself. The zygote is always the correct version and, by |
24 exec'ing one, we make sure the renderers have a different address space | 34 exec'ing one, we make sure the renderers have a different address space |
25 randomisation than the browser. | 35 randomisation than the browser. |
26 | 36 |
27 The zygote process is triggered by the `--type=zygote` command line flag, which | 37 The zygote process is triggered by the `--type=zygote` command line flag, which |
28 causes `ZygoteMain` (in `chrome/browser/zygote_main_linux.cc`) to be run. The | 38 causes `ZygoteMain` (in `chrome/browser/zygote_main_linux.cc`) to be run. The |
29 zygote is launched from `chrome/browser/zygote_host_linux.cc`. | 39 zygote is launched from `chrome/browser/zygote_host_linux.cc`. |
30 | 40 |
31 Signaling the zygote for a new renderer happens in | 41 Signaling the zygote for a new renderer happens in |
32 `chrome/browser/child_process_launcher.cc`. | 42 `chrome/browser/child_process_launcher.cc`. |
33 | 43 |
34 You can use the `--zygote-cmd-prefix` flag to debug the zygote process. If you | 44 You can use the `--zygote-cmd-prefix` flag to debug the zygote process. If you |
35 use `--renderer-cmd-prefix` then the zygote will be bypassed and renderers will | 45 use `--renderer-cmd-prefix` then the zygote will be bypassed and renderers will |
36 be exec'ed afresh every time. | 46 be exec'ed afresh every time. |
| 47 |
| 48 ## Appendix A: Runtime impact of relocations |
| 49 Measured on a Z620: |
| 50 |
| 51 $ LD_DEBUG=statistics /opt/google/chrome-beta/chrome --help |
| 52 runtime linker statistics: |
| 53 total startup time in dynamic loader: 73899158 clock cycles |
| 54 time needed for relocation: 56836478 clock cycles (76.9%) |
| 55 number of relocations: 4271 |
| 56 number of relocations from cache: 11347 |
| 57 number of relative relocations: 502740 |
| 58 time needed to load objects: 15789844 clock cycles (21.3%) |
| 59 |
| 60 56836478 clock cycles -> ~56 ms/GHz |
| 61 |
| 62 ## Appendix B: Memory impact of relocations |
| 63 |
| 64 $ readelf -WS /opt/google/chrome-beta/chrome |
| 65 [Nr] Name Type Address Off Size ES Flg
Lk Inf Al |
| 66 ... |
| 67 [25] .data.rel.ro PROGBITS 0000000006a8b590 6a8a590 5b5500 00 W
A 0 0 16 |
| 68 ... |
| 69 Note: 0x5b5500 -> 5.98 MB |
| 70 |
| 71 Actual impact in terms of memory pages that get shared due to CoW: |
| 72 |
| 73 $ cat /proc/.../smaps |
| 74 7fbdd1c81000-7fbdd2233000 r--p 06a5d000 fc:00 665771 /opt/google/chrome-
unstable/chrome |
| 75 ... |
| 76 Shared_Dirty: 5796 kB |
| 77 |
| 78 ## Appendix C: Overall memory impact |
| 79 $ cat /proc/$PID_OF_ZYGOTE/smaps | grep Shared_Dirty | awk '{TOTAL += $2} EN
D {print TOTAL}' |
| 80 8092 # KB for dirty pages shared with other processes (mostly forked child
processes). |
OLD | NEW |