Where Javascript Memory Management Ends and Angular $destroy Begins

A brief look inside the source code (inspired by this SO question)

Keep this example controller function in mind:


Javascript memory management — garbage collector

Memory will be allocated for an object when created.

You may then console.log(o.iThink) and ‘thereforeIAm’ will be read from its place in memory and printed to the console.

If you wanted to create a new string and lost the need for the {iThink: ‘thereforeIAm’} object, you may decide to overwrite o instead of introducing a new variable.

Fortunately, references (or lack thereof) send a clear message internally to javascript’s garbage collector as to whether a piece of finite memory should remain allocated or freed to perform other tasks. In this case, no reference remains to the object and string previously allocated for {iThink: ‘thereforeIAm’} and the corresponding memory may be freed (i.e. “garbage-collected”) as result.

Importantly, note that garbage collection happens internally. No code has to be written by you to that effect. All you need to concern yourself with is the value of o and the garbage collector can infer need, more or less, from remaining reference.


Angular memory management — $scope.$destroy

Unfortunately, the cleanup tasks related to $scope removal cannot be inferred by the javascript garbage collector based on reference alone; additional code is required.

That is because $scope objects embody a concept more complex than any ol’ javascript object. In particular, when no use remains in your application for a certain $scope object, no use must also remain for any associated $$watchers previously registered with the $scope.$watch method and no use must also remain for “children” $scope objects. The javascript garbage collector cannot infer this relationship from simple reference removal. Setting $scope to null will certainly clear the memory allocated directly for such object, but not much else can be accomplished.

In other words, the garbage collector has to be told what to do (and when to do it), which is exactly what the $scope.$destroy method does. Note these lines in particular:


The example controller function

When a function is invoked, the memory allocated for internally scoped objects will only remain allocated to the extent references remain past the life of the invocation (non-coincidentally, the essence of a closure).

In the example of the controller, uploader and reader objects are created and uploader is set to scope. No references remain to reader at all after the controller function is run, rendering reader eligible for garbage collection immediately thereafter. On the other hand, uploader is attached to an object that outlives the function’s invocation and so must remain an occupant of allocated memory until such object is destroyed. As a result, only a call to $scope.$destroy would enable the reallocation of memory once allocated to uploader as the lack of need cannot be inferred from reference alone.

Quote of the day:

Each product era can be divided into two phases: 1) the gestation phase, when the new platform is first introduced but is expensive, incomplete, and/or difficult to use, 2) the growth phase, when a new product comes along that solves those problems, kicking off a period of exponential growth. The Apple II was released in 1977 (and the Altair in 1975), but it was the release of the IBM PC in 1981 that kicked off the PC growth phase. The internet’s gestation phase took place in the 80s and early 90s when it was mostly a text-based tool used by academia and government. The release of the Mosaic web browser in 1993 started the growth phase, which has continued ever since.There were feature phones in the 90s and early smartphones like the Sidekick and Blackberry in the early 2000s, but the smartphone growth phase really started in 2007–8 with the release of the iPhone and then Android.
Chris Dixon