Two memory values, two resolutions
A page has two ways to learn about the machine's memory in Chromium. navigator.deviceMemory is the standard one. It is deliberately coarse: the value is rounded to a power of two and capped at 8, so a 12 GB laptop, a 16 GB desktop and a 64 GB workstation all report 8.
performance.memory is the older, non-standard one, still present in Chromium-based browsers. Its usedJSHeapSize and totalJSHeapSize describe the page's own usage and change all the time. Its jsHeapSizeLimit does not: it is the maximum size of the JavaScript heap, a constant for a given browser on a given machine.
That constant is not chosen by the page or the browser's settings. V8 computes it at startup from the physical memory the operating system reports.
How V8 sizes the heap
V8 gives the old generation a share of physical memory, so a machine with less RAM gets a smaller heap, and caps the result so that large machines do not reserve absurd amounts. On 64-bit desktop Chrome the measurements land on a small set of values:
- 7.5 GB of usable RAM: 4,127,195,136 bytes.
- About 7.8 GiB usable: 4,303,880,192 bytes. This is typical of a machine sold as 8 GB: firmware and integrated graphics reserve part of the memory, so the operating system reports a little under 8 GiB, and the limit lands just below the cap.
- 16 GB and 32 GB: 4,395,630,592 bytes, the cap. Anything above about 8 GiB reports the same value.
The cap and the step below it are where most desktop and laptop users are. That makes the value worth reading even though it carries only a few bits.
What it adds to deviceMemory
Read together, the two values constrain each other. A session that reports deviceMemory 4 should have a heap limit from the lower range, not the cap. A session that reports 8 should have one of the two top values. A heap limit at the cap with deviceMemory 2 describes a machine that does not exist.
The heap limit also separates machines that deviceMemory lumps together: an 8 GB laptop and a 16 GB desktop both say 8, but only one of them reports the cap. And because the value is fixed per machine, it adds to a fingerprint's stability across sessions.
A deployed challenge widget reads performance.memory inside a probe that also builds isolated iframes and checks security policies, and sends the limit to its server encoded in base 23. The encoding is cosmetic; the value is the one above.
Changing one without the other
Spoofing tools commonly override navigator.deviceMemory and leave performance.memory alone. On a 32 GB server presenting a 4 GB laptop, that leaves the heap limit at the cap: one value says small machine, the other says large one. Overriding jsHeapSizeLimit in JavaScript has the usual problems of any page-level patch, covered in timing native functions, and it has to happen in every realm, workers included.
Choosing the right value is its own problem. The cap is right for 8 GB and above only if the persona is a machine whose usable memory reaches it; an "8 GB" persona that reports the cap claims more usable memory than most 8 GB machines have. Clearcote's engine derives the limit from the persona's memory the way V8 does on real hardware, including the reserved slice, which is why its 8 GB personas report 4,303,880,192.
The through-line
The heap limit is a small example of the rule in anatomy of a browser fingerprint: every value that depends on the hardware has to come from the same imagined machine. Memory shows up in deviceMemory, in the heap limit, in the storage quota and in how many workers a page can run in parallel. A session that changes the first and forgets the rest has not changed its memory, only one report of it. Coherence over camouflage makes the general case.
