Memory Allocation in JavaScript

Memory Allocation in JavaScript

Before delving into memory allocation in JavaScript, it's important to have a solid understanding of the differences between primitive and non-primitive data types. The following table summarizes these differences clearly:

AspectPrimitiveNon-Primitive (Reference Types)
DefinitionData types that are immutable (cannot be changed) and hold a single value.Data types that are mutable (can be changed) and hold a reference to a memory location.
Examplesnumber, string, boolean, null, undefined, symbol, bigintobject, array, function, date, etc.
StorageStored directly in the stack memory.Stored in heap memory, with a reference in the stack.
MutabilityImmutable (their values cannot be changed).Mutable (their values or properties can be modified).
Memory AllocationEach variable holds its own copy of the value.Variables hold references (pointers) to the object in memory.
Pass ByPass-by-value: A copy of the value is passed when assigned or passed as function argument.Pass-by-reference: A reference to the object is passed, so changes affect the original object.
MethodsDo not have methods associated with them.Can have properties and methods (e.g., arrays and objects have functions like push(), toString(), etc.).
Example of Assignmentlet a = 5; let b = a;Both a and b are 5.let obj1 = { name: "John" }; let obj2 = obj1;Both obj1 and obj2 point to the same object.
Default Valueundefined (for uninitialized variables).null is often used as a placeholder for uninitialized or empty objects.

Key Points:

  • Primitives are immutable, meaning their values cannot be changed directly.

  • Non-Primitives (objects, arrays, etc.) are mutable and can be modified.

If you'd like to see a practical example or need further details, feel free to ask!

Memory Allocation

In JavaScript, memory is allocated into two main regions: Stack and Heap.

1. Stack Memory

  • Definition: A region of memory that stores primitive data types and references to objects (explained in heap memory section) stored in the heap.

  • Structure: Works on the LIFO (Last In, First Out) principle. Each function call gets its own stack frame.

Primitive Data Types

Primitive data types in JavaScript include Number, String, Boolean, Undefined, Null, BigInt, and Symbol. These are stored directly in the stack because they have fixed sizes.

Example with Primitives:

let a = 10;       // Stored directly in stack
let b = 30;       // Stored directly in stack
let c = a;        // `c` is assigned a copy of the value in `a`
a = 20;           // Changing `a` does not affect `c`

console.log(a);   // Output: 20
console.log(c);   // Output: 10

Explanation

  1. Variable Declarations (let a = 10; let b = 30;):

    • a and b are primitive types (Number in this case), so their values are stored directly in the stack.
  2. Assignment (let c = a;):

    • When you assign a to c, the value of a is copied to c.

    • This means c gets its own memory location in the stack, independent of a.

  3. Value Update (a = 20;):

    • When you update a, it only affects a's memory location in the stack.

    • c remains unchanged because it holds a copy of the value of a from the time of the assignment.

  4. Output (console.log(a); console.log(c);):

    • a has been updated to 20, so console.log(a) outputs 20.

    • c still holds the original value 10 (copied from a), so console.log(c) outputs 10.

2. Heap Memory

  • Definition: A region of memory used to store non-primitive data types like Objects, Arrays, Functions.

  • Structure: Provides a large, dynamic memory space for complex data structures. Unlike the stack, the heap is not organized in a strict order.

Non-Primitive Data Types

Objects and arrays are stored in the heap, and only their references are stored in the stack.

Example with Objects:

let obj1 = { 
    id: 20, 
    name: "Hridoy"
}; // Stored in heap, reference in stack

let obj2 = obj1;  // `obj2` gets the same reference as `obj1`

obj2.id = 35;  // Modifies the same object in the heap

console.log(obj1.id); // Output: 35
console.log(obj2.id); // Output: 35

Explanation

  1. Object Creation (let obj1 = {...};):

    • The object obj1 is a non-primitive type (an Object). Non-primitive values are stored in the heap memory.

    • However, the reference to this object (its memory location) is stored in the stack as part of the variable obj1.

  2. Assigning Reference (let obj2 = obj1;):

    • When obj2 is assigned obj1, it does not create a new copy of the object. Instead, obj2 points to the same memory location in the heap where the object is stored.

    • Both obj1 and obj2 now refer to the same object in the heap.

  3. Modifying the Object (obj2.id = 35;):

    • Since both obj1 and obj2 refer to the same object in memory, modifying the object through obj2 (i.e., obj2.id = 35) also updates the value of id in the same object.

    • This change will be reflected when one access the object through either obj1 or obj2.

  4. Output (console.log(obj1.id); console.log(obj2.id);):

    • After modifying the id property, both obj1 and obj2 reflect the same updated value, 35, because they both point to the same object in the heap.

    • Therefore, console.log(obj1.id) and console.log(obj2.id) will both output 35.

Key Differences Between Stack and Heap

FeatureStackHeap
StoragePrimitive data and referencesNon-primitive data (objects, arrays)
Access SpeedFastRelatively slower
StructureLinear (LIFO)Randomly allocated
LifetimeCleared automatically after function executionCleared by Garbage Collector
Data CopyingValue copyingReference copying

Example Combining Stack and Heap

function example() {
    let a = 5;                 // Primitive, stored in stack
    let b = a;                 // `b` gets a copy of `a`

    let objA = { val: 10 };    // Object, stored in heap
    let objB = objA;           // `objB` gets a reference to `objA`

    b = 10;                    // Changes `b` but not `a`
    objB.val = 20;             // Changes `objA.val` because both point to the same object

    console.log(a, b);         // Output: 5, 10
    console.log(objA.val);     // Output: 20
}

example();

Breakdown:

  1. a and b are primitives and stored in the stack.

  2. objA and objB are references stored in the stack, pointing to the same object in the heap.

  3. Modifying b does not affect a because they are independent values.

  4. Modifying objB.val also modifies objA.val because both point to the same object in the heap.

Garbage Collection

  • JavaScript uses Garbage Collection (GC) to free up heap memory no longer referenced.

  • When an object in the heap has no references pointing to it, it is eligible for garbage collection.

Example:

let obj = { name: "Jane" };
obj = null;  // The object becomes eligible for garbage collection

Why are Primitive Types Immutable and Reference Types Mutable?

Primitive Types (Immutable)

  • Immutability means that once a primitive value is created, it cannot be altered.

  • When one try to change a primitive value, a new value is created rather than modifying the original value.

  • Example:

let a = 10;       
let b = 30;       
let c = a;      
c = 'Hello';

In this example, c is initially assigned the value of a (which is 10). When you update c to 'Hello', the value of c is simply reassigned to a new value. The original value of a remains unchanged, because primitive values (like numbers) are immutable in JavaScript.

Why is this immutable?

  • Primitive types (like numbers, strings, booleans, etc.) are immutable, meaning their values cannot be modified once they're created. When you assign a primitive type to a new variable (like let c = a), you're creating a copy of the value, not a reference to the original.

  • In the code above, c is assigned the value of a (10), but later c is reassigned to 'Hello'. The value of a remains unchanged because reassigning c doesn't affect a. This is the key characteristic of immutability in primitive types: the original value isn't changed by assigning it to a new variable or updating the new variable.

Non-Primitive (Reference) Types (Mutable)

  • Mutability means that the value of a non-primitive data type can be changed after it is created.

  • JavaScript reference types include object, array, and function.

  • When one assign a reference type to another variable, both variables point to the same memory location. Modifying one variable affects the other because they refer to the same object in memory.

  • Example:

      let obj1 = { name: 'John' };
      let obj2 = obj1;
      obj2.name = 'Doe';
      console.log(obj1.name); // 'Doe' (obj1 is changed because both obj1 and obj2 refer to the same object)
    

    Here, obj1 and obj2 refer to the same object, so modifying obj2 also changes obj1.

Thanks for reading the blogs…