Small Integers vs. Heap Numbers in Chromium's V8 Engine

Chromium’s JavaScript engine, V8, differentiates between small integers (known as Smis) and heap numbers to drastically improve execution speed and reduce memory consumption. While the official JavaScript specification dictates that all numbers are 64-bit floating-point values, treating every single number this way would force the browser to constantly allocate memory and perform slow calculations for simple tasks like counting in a loop. To bypass this bottleneck, V8 splits numbers into two internal types: Smis, which are stored directly inside memory pointers for instant access, and heap numbers, which are allocated as separate objects in memory to handle decimals and massive integers.

The JavaScript Number Problem

According to the ECMAScript standard, JavaScript has only one number type: a double-precision 64-bit floating-point format (IEEE 754). In practice, however, developers mostly use whole numbers for everyday tasks like array indexing, loop counters, and basic math.

If V8 strictly followed the specification at the hardware level, every time a number was created or modified, the engine would have to allocate a 64-bit chunk of memory on the heap, store the value there, and create a pointer to that memory address. Doing this millions of times per second would overwhelm the system's memory and drastically slow down the browser.

How Pointer Tagging Works

To separate small integers from heap numbers, V8 uses a technique called pointer tagging. In modern 32-bit and 64-bit system architectures, memory addresses are aligned, meaning the binary representation of any valid memory pointer always ends in zeroes.

V8 exploits this predictable behavior by using the last bit (the least significant bit) of a memory address as a "tag" rather than part of the address itself:

  • If the last bit is 0, V8 reads the remaining bits as the actual value of a Small Integer (Smi).
  • If the last bit is 1, V8 reads the remaining bits as a memory address pointing to an object on the heap, such as a Heap Number.

Small Integers (Smis)

A Smi is a signed whole number that fits directly inside a single CPU register alongside its tag bit. On a 32-bit system (or when V8 uses pointer compression on 64-bit systems), a Smi uses 31 bits for the integer and 1 bit for the tag, allowing it to represent whole numbers from -1,073,741,824 to 1,073,741,823.

Smis provide two massive advantages:

  1. Zero Memory Allocation: Because the number is stored directly inside the variable container itself, V8 does not need to allocate extra space in the heap.
  2. Instant CPU Access: The processor can read and modify the number immediately without having to follow a pointer to another location in RAM (a slow process known as pointer dereferencing).

Heap Numbers

When a number cannot fit into the Smi format, V8 falls back to creating a Heap Number. This applies to:

  • Numbers with decimal points (e.g., 3.14).
  • Integers outside the 31-bit Smi range.
  • Special numeric values like NaN (Not-a-Number), Infinity, and -0.

A Heap Number is a full 64-bit floating-point value wrapped inside a dedicated memory object. The variable holds a pointer (ending in bit 1) that directs the engine to the location on the heap where the actual 64-bit number lives. Furthermore, Heap Numbers are immutable; if you add 1.5 to 2.5, V8 must allocate a brand-new Heap Number object to store the 4.0 result.

Impact on Performance and Garbage Collection

Differentiating between these two types is critical for browser performance. At the hardware level, CPUs execute integer arithmetic significantly faster than floating-point math. By keeping loop counters and array indices as Smis, V8 translates JavaScript directly into ultra-fast CPU integer instructions.

Additionally, this separation prevents the Garbage Collector (GC) from freezing the browser. Every Heap Number created must eventually be tracked down and deleted by the GC when it is no longer needed. Because Smis never touch the heap, they completely bypass the garbage collection process, saving substantial processing power and keeping web applications running smoothly.