V8 Garbage Collector
Mood
thoughtful
Sentiment
positive
Category
tech
Key topics
V8
Garbage Collection
JavaScript
Performance Optimization
The article discusses recent improvements and developments in V8's garbage collector, highlighting its evolution over the last couple of years.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
1h
Peak period
33
Day 1
Avg / period
12
Based on 36 loaded comments
Key moments
- 01Story posted
11/14/2025, 9:53:13 AM
5d ago
Step 01 - 02First comment
11/14/2025, 11:10:07 AM
1h after posting
Step 02 - 03Peak activity
33 comments in Day 1
Hottest window of the conversation
Step 03 - 04Latest activity
11/17/2025, 8:53:45 AM
2d ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
The conversation-leading-up-to-that played out a bit like this in my head:
Google Engineer #1: Hey, shouldn't that length field be unsigned? Not like a negative value ever makes sense there?
GE#2: Style guide says no
GE#1: Yeah, but that could easily be exploited, right?
GE#2: Maybe, but at least I won't get dinged on code review: my metrics are already really lagging this quarter
GE#1: Good point! In fact, I'll pre-prepare an emergency patch for that whole thing, as my team lead indicated I've been a bit slow on the turnaround lately...
> The fact that unsigned arithmetic doesn't model the behavior of a simple integer, but is instead defined by the standard to model modular arithmetic (wrapping around on overflow/underflow), means that a significant class of bugs cannot be diagnosed by the compiler.
Fair enough, but signed arithmetic doesn't model the behavior of a "simple integer" (supposedly the mathematical concept) either. Instead, overflow in signed arithmetic is undefined behavior. Does that actually lead to the compiler being able to diagnose bugs? What's the claimed benefit exactly?
At least I believe Java decided on signed integers for similar reasons. But if it's indeed UB in C++, it doesn't make sense.
This leads to fun behavior. Consider these functions which differ only in the type of the loop variable:
int foo() {
for (int i = 1; i > 0; ++i) {}
return 42;
}
int bar() {
for (unsigned i = 1; i > 0; ++i) {}
return 42;
}
If you compile these with GCC with optimization enabled, the result is: foo():
.L2:
jmp .L2
bar():
mov eax, 42
ret
That is, foo() gets compiled into an infinite loop, while the loop in bar() is eliminated instead. This is because the compiler may assume only in the first case that i will never overflow.> One of the little experiments I tried was asking people about the rules for unsigned arithmetic in C. It turns out nobody understands how unsigned arithmetic in C works. There are a few obvious things that people understand, but many people don't understand it.
-- https://www.artima.com/articles/james-gosling-on-java-may-20...
#include <stdckdint.h>So if you use a signed integer, there is a chance that overflows are caught in tests.
1. https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
Implicitly casting to either signed or unsigned integer is allowed and does not generate a warning.
Also in Zig overflow is illegal for both signed and unsigned integers, and guaranteed to be detected when building in Safe mode (but not in Fast mode). There is a separate set of operators for wrapping arithmetic.
Ideally there'd be a third type for unsigned-non-wrapping-integer (and llvm even supports a UB-on-unsigned-wrapping flag for arith ops in its IR that largely goes unused for C/C++), but alas such doesn't exist. Half-relatedly, this previously appeared as a discussion point on Linux (though Linus really did not like the concept of multiple unsigned types and as such it didn't go anywhere iirc).
> From what I can tell, there have been about 4 FTE from Google over this period
Though in this context it just seems to be the number of people working on the code on a consistent basis.
* “Full Time Employee” (which can itself mean “not a part-timer” in a place that employs both, or “not a temp/contractor” [in which case the “full-time” really means “regular/permanent”]) or
* “Full Time Equivalent” (a budgeting unit equal to either a full time worker or a combination of part time workers with the same aggregate [usually weekly] hours as constitute the standard for full-time in the system being used.)
This is the case at many companies to avoid contractors being considered employees.
It's a measure of time spent working on something, to standardise comparisons of work capacity and acknowledge that it's not always full time, especially when aggregating the time from different people. One full time person = 1 FTE.
For example if you work 20 hours a week on project A and 20 hours on project B, then project A will count your contribution as 0.5 FTE while you're assigned to that project.
If you also have two other people working on it full timee, and a project manager working 1 day a week on it, then project A will count the contribution from all three of you as 2.7 FTE. (2.7 = 0.5 + 2 + 0.2).
Don't get me wrong, I'm aware V8 wasn't designed with games in mind. QuickJS (which is also supported by GodotJS) is probably the safer bet. Or you know, not JavaScript at all. However, I'm building tooling specifically for kids to make games, and TypeScript is leagues ahead in terms of usability:
https://breaka.club/blog/why-were-building-clubs-for-kids
Before I make the swap to QuickJS out of necessity, I was hoping to try my hand at tuning V8's GC for my use case. I wasn't expecting this to be easy, but the article doesn't exactly instill me with confidence:
> Simply tuning the system appears to involve a dose of science, a dose of flailing around and trying things, and a whole cauldron of witchcraft. There appears to be one person whose full-time job it is to implement and monitor metrics on V8 memory performance and implement appropriate tweaks. Good grief!
If anyone reading this has experience with tuning V8's GC to minimize stop-the-world GC duration (at the cost of overall memory use, or runtime performance etc.) I'd greatly appreciate any advice that can be offered.
So, yeah, I should really give it a shot. Thanks for the reminder.
V8 has its first module in Rust and I'm sure more are coming, but it's not necessarily an easy integration.
JS is a GCed language. Are there good examples of Rust interacting well with a GCed language runtime where it is able to free unreachable cross domain pointer cycles? Like a JS object that has a reference to a Rust object, which itself has a reference to a JS object. Add more steps and hopefully you can see that collecting such cycles is a hard problem. This is the problem the C++ GC solves.
By the way you can't always break cycles with weak pointers. The browser standards have semantics you have to adhere to.
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.