1

I'm just wondering if the following code snippet is a potential memory leak.

let arrOfObj = [
    { a: 0, b: 0 }
]

const copy = [ ...arrOfObj ]
copy[0].a = 5;
console.log(arrOfObj)
// [ { a: 5, b: 0 } ]
console.log(copy)
// [ { a: 5, b: 0 } ]

arrOfObj = []
console.log(arrOfObj)
// []
console.log(copy)
// [ { a: 5, b: 0 } ]

The spread operator will only do a shallow copy, so the object inside the array would be a reference. But where did javascript get the values in the last log? Will they garbage collected as I empty the array?

Leon Braun
  • 385
  • 5
  • 11
  • 2
    You didn’t empty any array. You just reassigned the `arrOfObj` variable to a new array. See [How do I empty an array in JavaScript?](/q/1232040/4642212). – Sebastian Simon Feb 01 '22 at 13:32
  • After your statement 2, copy and arrOfObj are two seperate arrays. The object inside is the same. Anything you do to the **array** itself after that, will not change anything in the other array. Only the object reference is the same – Tushar Shahi Feb 01 '22 at 13:36
  • Nothing in the global scope is garbage collected. – Teemu Feb 01 '22 at 13:49

1 Answers1

3

No, there is no memory leak. Breaking down the steps for better explanation:

  1. const copy = [...arrOfObj] : allocates space in memory heap and assign it to copy variable. Since, spread performs shallow copy, the object reference is still same inside of the array.
  2. copy[0].a = 5; : updates the value of the object inside of copy array. Since, the reference to object is same for both copy and arrOfObj, it is reflected in both the arrays.
  3. arrOfObj = [] : allocates space in memory heap for [] and assigns it to arrOfObj variable. This does not imply that copy loses its reference to the array you created earlier. copy still points to the older memory reference. Hence, copy prints out the older array containing object, and arrOfObj prints empty array.

To ellaborate more on this, even if you do the following, copy would still point to older memory reference :

let arrOfObj = [
    { a: 0, b: 0 }
]

// instead of spread, assign it directly 
const copy = arrOfObj;
copy[0].a = 5;
console.log(arrOfObj)
// [ { a: 5, b: 0 } ]
console.log(copy)
// [ { a: 5, b: 0 } ]

// assign empty array to 'arrOfObj'
arrOfObj = []
console.log(arrOfObj)
// []
console.log(copy)
// [ { a: 5, b: 0 } ] => still prints the array

Also, the older value of arrOfObj "may" get garbage collected (depends on JS engine optimisations)

Kanishk Anand
  • 1,686
  • 1
  • 7
  • 16
  • 1
    To elaborate on the "why?": Variables/Constants in JS do not hold a value by themselves, they are all references to anonymous values in memory. With an assignment like `x = 5;`, you technically do not say "put value 5 into variable `x`", you say "here is the value 5, let variable `x` reference it". The previous value referenced by variable `x` is now somewhere in memory and will be garbage collected when no variable/datastructure references it anymore. (In languages without garbage collector (e.g. Pascal), it would be technically correct to say "put value 5 into variable `x`") – orithena Feb 01 '22 at 14:08
  • So, it is save to work with the copy cause it "may" be garbage collected? – Leon Braun Feb 01 '22 at 14:42
  • @LeonBraun no, `copy` will always refer to the value, hence, it should be safe to use. I was referring to the old value of `arrOfObj` which can potentially get garbage collected. – Kanishk Anand Feb 01 '22 at 16:34