Try   HackMD

Day26 Memory Management In JavaScript (V8)

Each time you create an object, memory is allocated, but since memory is limited, V8 recycles the memory for you through garbage collection.

Garbage Collector

A garbage collector must perform several tasks:

  1. Identify live/dead objects(標記)
  2. Recycle/reuse the memory(回收) occupied by dead objects
  3. Compact/defragment memory (optional) 重組: The collector may also rearrange memory to save space and improve memory efficiency.
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

When the GC is triggered, it pauses the main thread to reclaim memory. This process is known as stop-the-world garbage collection (or GC pauses). In some cases, a particularly long GC cycle can last several hundred milliseconds, potentially affecting performance.

Marking

To identify live and dead objects, marking is used:

  • Start at root pointers (like the stack and global objects in JavaScript).
  • Traverse all references (or pointers) to objects in the heap.
  • Mark every object encountered as live.
  • Objects that aren't marked as live are considered dead and can be collected.
  • The time complexity depends on the number of live objects, not the total number of allocated objects.

Visualizing the Marking Process

  • Stack: Holds static locals and manages the execution flow of the program.

  • Heap: V8 splits the heap into pages, each page being 512 kilobytes in size.

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • Think of memory as a graph with primitive types and objects.

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • A value’s retaining path(s)

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • Removing a value from the graph

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • Garbage: All values which cannot be reached from the root node or Values that no longer have a retaining path from the root node.

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • A value's retained size: the amount of memory that would be freed if a value and all its dependent objects were garbage collected.

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Generational Heap layout

V8 uses a generational heap structure to manage memory efficiently, splitting objects into two main generations: the young generation and the old generation.

Objects are first allocated into the 'nursery'. If they survive the next GC, they remain in the young generation but are considered ‘intermediate’. If they survive yet another GC, they are moved into the old generation.

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Garbage Collectors: Minor GC (Scavenger)

to clean up the young generation

  1. Marking Phase: Objects are marked for survival based on references from the stack and global objects.

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  2. Evacuation(疏散):

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Semi-Space Design: The nursery is divided into two halves, From-Space and To-Space.

    • From-Space holds the current objects
    • To-Space remains empty until objects are copied into it.
    1. Copy live objects from From-Space into To-Space.
    2. A mark (circle) is placed on the objects in To-Space to indicate they were moved
  3. Freeing From-Space:

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    • Once all live objects have been copied to To-Space, anything left in From-Space is considered implicitly dead.
    • This makes From-Space completely free for future use.
  4. Updating References:

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  5. Flipping

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    To-Space becomes the new nursery, and From-Space is freed.

  6. New Allocations

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Garbage Collectors: Major GC (Full Mark-Compact)

to clean up the whole heap

  1. Marking Phase

  2. Sweeping to freelist

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • GC finds contiguous gaps left by unreachable objects
  • These gaps are added to a data structure called a free-list, which organizes free memory chunks by size.
  • When a new object needs to be allocated, the GC uses the free list to find a suitable chunk of space.
  1. Defragmenting Memory - Compacting 記憶體碎片整理
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →
  • The major GC also chooses to evacuate/compact some pages, based on a fragmentation heuristic(一種算法).
  • Surviving objects from fragmented pages are copied to fresh page, using the free-list to locate available space.
  • This is similar to hard-disk defragmentation on an old PC. (磁碟重組)
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

The Generational Hypothesis 假說

  • Most objects die young: This means that most objects are allocated and quickly become unreachable from the perspective of the garbage collector (GC)
    • This principle holds not only for V8 or JavaScript, but for most dynamic languages like Python, PHP.
  • A small percentage of objects live long and tend to survive many GC cycles.

V8's generational heap layout is designed to take advantage of this hypothesis.

  • The GC only copies objects that survive garbage collection, reducing overall cost.
  • Since only a small percentage of objects survive a GC cycle, this leads to minimal overhead.
  • Conversely, this makes long-live objects more expensive(copy them twice), copying can be expensive!

Orinoco

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Orinoco is the codename of a GC project aimed at transforming a purely sequential garbage collection system into a mostly concurrent and parallel GC. With the goal Free the main thread.

Terminology for Orinoco

  • Parallel
    The main thread and helper threads work on the same task at the same time.

    • Still ‘stop-the-world‘
    • Reduces the atomic pause by factor N
      Image Not Showing Possible Reasons
      • The image was uploaded to a note which you don't have access to
      • The note which the image was originally uploaded to has been deleted
      Learn More →
  • Incremental 增量
    Small chunks of the GC task are interleaved into the main thread execution.

    • The Js heap will change between GC work
    • Better main thread latency!
      Image Not Showing Possible Reasons
      • The image was uploaded to a note which you don't have access to
      • The note which the image was originally uploaded to has been deleted
      Learn More →
  • Concurrent
    GC tasks happen entirely in the background. The main thread is free to run JavaScript.

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

State of GC in V8

Parallel Scavenging

Pasted 2024-09-09-05-16-05
Parallel scavenging distributes scavenging work across multiple helper threads and the main thread.

  • The main thread and up to 7 helper threads are used
  • GC Trigger: A scavenge is triggered when the From space in the new generation (nursery) runs out of memory.

Major GC

Pasted 2024-09-09-05-25-28

  • The major GC uses concurrent marking and sweeping, and parallel compaction and pointer updating.

  • GC Trigger: dynamically computes a heap limit for the next GC cycle.

    Screenshot 2024-09-09 at 4.03.47 PM

    • The heap starts small and grows over time based on the application's memory needs.
    • Based on these factors, the GC dynamically computes a heap limit for the next GC cycle.
      1. Allocation Rate: How frequently objects are allocated.
      2. Survival Rate: The percentage of objects being promoted from the new generation to the old generation.

Conclusion

Orinoco has optimized much of the GC work, so most developers don’t need to worry about it in JavaScript. However, understanding some internals can improve memory usage and programming patterns. General patterns apply to all GC language—for example, short-lived objects are cheap for GC, and it's important to avoid leaking memory to the global object or through contexts. Don’t be afraid to allocate short-lived objects, as GC handles them efficiently.

參考來源:
https://v8.dev/blog/trash-talk#major-gc
https://www.youtube.com/watch?v=LaxbdIyBkL0
https://www.youtube.com/watch?v=OG_AZnPokGw&t=482s
https://github.com/addyosmani/memory-mysteries?tab=Apache-2.0-1-ov-file