Skip to main content

Overview

JSValue represents a JavaScript value which can be a primitive type or an object. QuickJS uses reference counting for memory management, so it is important to explicitly manage JSValue lifetimes.

JSValue representation

QuickJS uses NAN boxing on 64-bit systems to store values efficiently:
  • Integers, booleans, and small values are stored inline
  • Objects, strings, and other heap-allocated types are stored as pointers
  • All values fit in a 64-bit word

Value tags

Each JSValue has a tag identifying its type:
Tags with negative values (object, string, symbol, bigint) use reference counting. Primitive types (int, bool, null, undefined) do not require reference counting.

Reference counting

QuickJS uses reference counting for memory management. This means:
  • Each object tracks how many references point to it
  • When you create or copy a reference, increment the count
  • When you’re done with a reference, decrement the count
  • When the count reaches zero, the object is freed

Core functions

Ownership rules

Critical rule: A function with a JSValue parameter takes ownership; caller must NOT call JS_FreeValue. A function with a JSValueConst parameter does NOT take ownership; caller MUST call JS_FreeValue when done.

Return value ownership

  • Functions returning JSValue transfer ownership to caller
  • Caller must call JS_FreeValue() on the returned value
  • Functions returning JSValueConst do not transfer ownership

Common patterns

Creating and freeing values

Passing to functions

Error handling

Memory efficiency

Stack vs. heap allocation

Constant values

QuickJS provides pre-defined constant values that don’t need to be freed:
These can be used directly without calling JS_FreeValue():

Common mistakes

Double free

Memory leak

Using after free

Correct version:

Garbage collection

While QuickJS uses reference counting, it also has a garbage collector to handle reference cycles:
The GC only runs for cyclic structures. Simple reference-counted objects are freed immediately when their count reaches zero.

Best practices

Rule of thumb: If a function returns a JSValue, you own it and must free it. If it takes a JSValue parameter, it owns it and you shouldn’t free it.
Use-after-free detector: Build with -DJS_CHECK_JSVALUE to enable compile-time checks that help catch ownership bugs.
Always check for exceptions after calling functions that can fail. Exception values must be freed with JS_FreeValue().

See also