Search code examples
javascriptmemorygarbage-collectionheap-memory

Does garbage collector work on overriden or "nullified" memoized values in javascript?


I am sorry is something similar has been asked, the search didn't find it.

Let's say I have function that creates a big memoized value in js, in the example an array of 1 million random numbers, and call that function twice, so I have two big arrays.

  const memoizedValue = () => {
    const val = [...Array(1000000)].map((_, i) => i + Math.random())
    const valAtIndex = i => val[i];
    return valAtIndex;
  }
  let valAtIndex1 = memoizedValue();
  console.log(valAtIndex1(1000)) // 1000.9215271184725
  console.log(valAtIndex1(1001)) // 1001.123987792151
  let valAtIndex2 = memoizedValue();
  console.log(valAtIndex2(1000)) // 1000.8830808003901
  console.log(valAtIndex2(1001)) // 1001.3989636036797

Do I remove the array if I clear a reference to the instance? Does the garbage collector clear the memory for the array if I do this (asuming I don't have any other instance):

valAtIndex1 = (i) => i;
console.log(valAtIndex1(1000)) // 1000
console.log(valAtIndex1(1001)) // 1001

What if I asign the value null, does this clear the memory for the Array?

valAtIndex1 = null;

Solution

  • If you release all references to the function you've put in valAtIndex1 (for instance, by doing valAtIndex1 = x where x can be literally anything as long as it's not the value valAtIndex1 already has in it — null, undefined, 42, ...), that releases that function's reference to the context where it was created, which in turn releases that context's reference to the big array. The garbage collector is free to reclaim that memory.

    For example:

    let valAtIndex = memoizedValue();
    console.log(valAtIndex(0)); // 1.3753751200626736 or whatever
    valAtIndex = null;          // Releases the reference
    

    In the comments you seemed particularly concerned about overwriting the variable's value with the result of another call to memoizedValue. That's absolutely fine:

    let valAtIndex = memoizedValue(); // Creates array A and function A accessing it
    console.log(valAtIndex(0));       // 1.3753751200626736 or whatever
    valAtIndex = memoizedValue();     // Creates array B and function b accessing it,
                                      // releasing the reference to function A
    console.log(valAtIndex(0));       // 1.6239617464592875 or whatever
    

    Side note: Your code to create the massive array will create an unnecessary temporary massive array (the one you're creating with the array literal), and possibly two of them (the one you're creating with Array(1000000) may well reserve memory for all one million array elements; it does in V8, for instance, even though the array is empty). Instead:

    const val = Array.from({length: 1000000}, (_, i) => i + Math.random());