WEBVTT

1
00:00:01.050 --> 00:00:04.980
<v Jonas>Welcome back to part two of Memory Management.</v>

2
00:00:04.980 --> 00:00:09.240
And this one is all about how memory is released.

3
00:00:09.240 --> 00:00:11.850
In particular, we're gonna dive deep into

4
00:00:11.850 --> 00:00:14.790
how a mechanism called garbage collection works

5
00:00:14.790 --> 00:00:16.290
behind the scenes in order

6
00:00:16.290 --> 00:00:18.993
to keep our memory clean and healthy.

7
00:00:20.130 --> 00:00:24.720
So remember how in JavaScript each value that we create goes

8
00:00:24.720 --> 00:00:29.100
through a memory lifecycle where first memory is allocated

9
00:00:29.100 --> 00:00:33.660
for the value, then the allocated piece of memory is used.

10
00:00:33.660 --> 00:00:36.300
And finally, when no longer needed,

11
00:00:36.300 --> 00:00:39.240
the piece of memory is released.

12
00:00:39.240 --> 00:00:42.570
Now, we already talked in depth about step one,

13
00:00:42.570 --> 00:00:44.580
step two is pretty obvious,

14
00:00:44.580 --> 00:00:47.280
so there's actually nothing to learn there,

15
00:00:47.280 --> 00:00:50.490
and so let's now turn our attention to the way

16
00:00:50.490 --> 00:00:52.530
in which memory is released

17
00:00:52.530 --> 00:00:55.533
in the JavaScript engine in step three.

18
00:00:56.940 --> 00:00:59.250
Basically, we're gonna answer the question,

19
00:00:59.250 --> 00:01:01.260
how is memory freed up

20
00:01:01.260 --> 00:01:04.710
after we no longer need a certain value?

21
00:01:04.710 --> 00:01:08.190
Now, since these values are stored in the stack

22
00:01:08.190 --> 00:01:10.260
and the heap, we need to analyze

23
00:01:10.260 --> 00:01:13.200
both these storage mechanisms.

24
00:01:13.200 --> 00:01:17.250
So first off, in the call stack, it's all very simple

25
00:01:17.250 --> 00:01:19.140
because the variable environments

26
00:01:19.140 --> 00:01:22.620
where primitives are stored are simply deleted

27
00:01:22.620 --> 00:01:26.613
when the corresponding execution context pops off the stack.

28
00:01:27.690 --> 00:01:30.300
As an example, here is the call stack

29
00:01:30.300 --> 00:01:32.490
with the global execution context

30
00:01:32.490 --> 00:01:36.120
and two additional ones for two function calls.

31
00:01:36.120 --> 00:01:39.570
The global execution context has the X variable,

32
00:01:39.570 --> 00:01:43.080
which is clearly a primitive, and the execution context

33
00:01:43.080 --> 00:01:47.490
of the calcAge function has variables Y and Z.

34
00:01:47.490 --> 00:01:50.670
So these three variables are clearly stored

35
00:01:50.670 --> 00:01:52.080
in the call stack.

36
00:01:52.080 --> 00:01:56.400
And so then as the execution context pops off the stack,

37
00:01:56.400 --> 00:01:59.400
the variable environment of the calcAge function

38
00:01:59.400 --> 00:02:02.250
will just be removed from memory

39
00:02:02.250 --> 00:02:04.410
together with the execution context

40
00:02:04.410 --> 00:02:06.870
that just popped off the stack.

41
00:02:06.870 --> 00:02:10.170
So as I said, very simple, right?

42
00:02:10.170 --> 00:02:12.150
Variables are simply stored

43
00:02:12.150 --> 00:02:14.760
in an execution context in the call stack,

44
00:02:14.760 --> 00:02:19.230
and as soon as the context is gone, so are the variables,

45
00:02:19.230 --> 00:02:21.150
and the memory that they occupied

46
00:02:21.150 --> 00:02:23.955
is simply released for future usage.

47
00:02:23.955 --> 00:02:27.270
Now, notice what happens with the X variable

48
00:02:27.270 --> 00:02:29.760
in the global execution context.

49
00:02:29.760 --> 00:02:33.180
Since this execution context never disappears,

50
00:02:33.180 --> 00:02:36.780
this value will stay in the stack forever.

51
00:02:36.780 --> 00:02:40.050
Now, this is no big deal, I just wanted to make it clear

52
00:02:40.050 --> 00:02:44.310
that global variables will of course never be deleted,

53
00:02:44.310 --> 00:02:47.340
which is pretty intuitive, I think.

54
00:02:47.340 --> 00:02:50.340
Okay, but now let's move on to the heap

55
00:02:50.340 --> 00:02:54.750
where memory management is considerably more complex.

56
00:02:54.750 --> 00:02:59.190
In order to delete old unused objects from the heap

57
00:02:59.190 --> 00:03:03.030
and free up memory, JavaScript engines employ a process

58
00:03:03.030 --> 00:03:05.250
called garbage collection.

59
00:03:05.250 --> 00:03:07.950
This garbage collection is the central tool

60
00:03:07.950 --> 00:03:11.550
for memory management in any JavaScript engine.

61
00:03:11.550 --> 00:03:13.740
And notice how I said engine here,

62
00:03:13.740 --> 00:03:15.630
because it's indeed the engine

63
00:03:15.630 --> 00:03:18.540
that runs garbage collection automatically

64
00:03:18.540 --> 00:03:20.460
whenever it sees fit.

65
00:03:20.460 --> 00:03:24.090
We developers cannot control when the heap memory

66
00:03:24.090 --> 00:03:26.340
is cleared by garbage collection,

67
00:03:26.340 --> 00:03:28.590
which is actually a great thing,

68
00:03:28.590 --> 00:03:31.170
because this automatic memory management

69
00:03:31.170 --> 00:03:33.930
makes our lives a lot easier.

70
00:03:33.930 --> 00:03:36.750
So you can basically think of garbage collection

71
00:03:36.750 --> 00:03:40.530
as an automatic cleaning service that comes into your house

72
00:03:40.530 --> 00:03:45.210
from time to time and identifies and removes old stuff

73
00:03:45.210 --> 00:03:47.686
that no one is using anymore.

74
00:03:47.686 --> 00:03:50.340
But anyway, there are different ways

75
00:03:50.340 --> 00:03:52.350
to implement garbage collection,

76
00:03:52.350 --> 00:03:54.870
but all modern engines use an algorithm

77
00:03:54.870 --> 00:03:56.880
called mark-and-sweep.

78
00:03:56.880 --> 00:03:59.670
And so let's now quickly check out how it works

79
00:03:59.670 --> 00:04:03.630
by bringing back the call stack and heap.

80
00:04:03.630 --> 00:04:06.660
Now, first of all, here in red and green

81
00:04:06.660 --> 00:04:09.690
we have objects called hobbies and tasks,

82
00:04:09.690 --> 00:04:12.090
and so as we just learned previously,

83
00:04:12.090 --> 00:04:15.030
these variables actually store references

84
00:04:15.030 --> 00:04:18.690
to the actual object stored in the heap.

85
00:04:18.690 --> 00:04:21.810
Let's now also say that the red object references

86
00:04:21.810 --> 00:04:24.120
some other object, which, of course,

87
00:04:24.120 --> 00:04:26.130
is also stored in the heap,

88
00:04:26.130 --> 00:04:30.540
and the green object references just another object.

89
00:04:30.540 --> 00:04:33.060
And by the way, I keep saying objects

90
00:04:33.060 --> 00:04:34.560
that are stored in the heap,

91
00:04:34.560 --> 00:04:36.360
but as we just learned earlier,

92
00:04:36.360 --> 00:04:38.760
these can actually be not just objects,

93
00:04:38.760 --> 00:04:40.800
but also erase, functions,

94
00:04:40.800 --> 00:04:45.300
and other data structures like sets or maps.

95
00:04:45.300 --> 00:04:49.890
Now, okay, but now back to the mark-and-sweep algorithm.

96
00:04:49.890 --> 00:04:52.080
The first step of garbage collection

97
00:04:52.080 --> 00:04:56.100
with the mark-and-sweep algorithm is the mark phase

98
00:04:56.100 --> 00:04:58.110
where all objects that are reachable

99
00:04:58.110 --> 00:05:02.220
from a so-called root are marked as alive.

100
00:05:02.220 --> 00:05:04.740
Now, roots are basically starting points

101
00:05:04.740 --> 00:05:07.080
from which the algorithm starts to look

102
00:05:07.080 --> 00:05:10.800
for alive or reachable objects.

103
00:05:10.800 --> 00:05:13.050
And different things can be roots,

104
00:05:13.050 --> 00:05:17.070
but the most obvious ones are the global execution context,

105
00:05:17.070 --> 00:05:19.050
which is always present,

106
00:05:19.050 --> 00:05:23.220
and any other execution context of running functions.

107
00:05:23.220 --> 00:05:26.760
So again, the algorithm starts looking for objects

108
00:05:26.760 --> 00:05:29.373
in these places called roots.

109
00:05:30.330 --> 00:05:33.360
In this example, the green and red objects

110
00:05:33.360 --> 00:05:36.930
are obviously alive because they can be reached

111
00:05:36.930 --> 00:05:38.640
from one of the roots.

112
00:05:38.640 --> 00:05:42.540
And the same is true for the blue and gray objects.

113
00:05:42.540 --> 00:05:45.990
They're also alive because they can also be reached

114
00:05:45.990 --> 00:05:49.350
from one of the other reachable objects.

115
00:05:49.350 --> 00:05:51.990
But now let's take it one step further,

116
00:05:51.990 --> 00:05:54.090
because an object can be reached

117
00:05:54.090 --> 00:05:57.090
by more than just the global execution context

118
00:05:57.090 --> 00:06:00.060
or one of the other contexts in the stack.

119
00:06:00.060 --> 00:06:04.380
They can also be reached by event listeners or active timers

120
00:06:04.380 --> 00:06:07.260
or by something that we call closures.

121
00:06:07.260 --> 00:06:10.230
And more about closures later.

122
00:06:10.230 --> 00:06:12.810
So these two are also roots

123
00:06:12.810 --> 00:06:15.570
for the mark-and-sweep algorithm.

124
00:06:15.570 --> 00:06:18.780
And now let's say that we have this purple object

125
00:06:18.780 --> 00:06:21.480
that is referenced and therefore reachable

126
00:06:21.480 --> 00:06:24.720
from an active timer and this yellow object

127
00:06:24.720 --> 00:06:27.240
that is reachable from a closure.

128
00:06:27.240 --> 00:06:30.240
So both these are alive as well.

129
00:06:30.240 --> 00:06:33.750
And now finally, just to make this a bit more complete,

130
00:06:33.750 --> 00:06:37.080
let's imagine that we also have this pink object

131
00:06:37.080 --> 00:06:40.650
in the heap, which isn't being referenced by anything.

132
00:06:40.650 --> 00:06:43.650
And so this one is not marked as alive

133
00:06:43.650 --> 00:06:47.160
because it cannot be reached by any of the roots.

134
00:06:47.160 --> 00:06:51.319
So we can basically say that this one is dead.

135
00:06:51.319 --> 00:06:53.430
Okay, so with this,

136
00:06:53.430 --> 00:06:56.700
we basically just simulated the mark phase.

137
00:06:56.700 --> 00:07:00.210
So phase one in the mark-and-sweep algorithm.

138
00:07:00.210 --> 00:07:02.610
The second phase is the sweep phase

139
00:07:02.610 --> 00:07:06.030
where all the unmarked objects, or in other words,

140
00:07:06.030 --> 00:07:09.930
all the unreachable objects, are simply deleted.

141
00:07:09.930 --> 00:07:13.320
Basically, the algorithm has decided in the first step

142
00:07:13.320 --> 00:07:15.840
that these objects are no longer needed

143
00:07:15.840 --> 00:07:18.990
and that the memory occupied by them can be reclaimed

144
00:07:18.990 --> 00:07:23.990
and used for future memory allocations for future objects.

145
00:07:24.060 --> 00:07:27.270
So to simulate this in our example here,

146
00:07:27.270 --> 00:07:31.470
right now we only have one object that is unreachable,

147
00:07:31.470 --> 00:07:34.140
and that's the pink object.

148
00:07:34.140 --> 00:07:37.170
So what's gonna happen in this phase?

149
00:07:37.170 --> 00:07:40.489
Well, that's right, the pink object will be deleted

150
00:07:40.489 --> 00:07:43.620
and the memory will be reclaimed.

151
00:07:43.620 --> 00:07:47.250
And so just like this, the automatic garbage collection

152
00:07:47.250 --> 00:07:50.820
has insured that our memory stays nice and clean

153
00:07:50.820 --> 00:07:52.770
and not cluttered with objects

154
00:07:52.770 --> 00:07:55.200
that can no longer be accessed anyway

155
00:07:55.200 --> 00:07:58.653
and that we therefore no longer need in the heap.

156
00:07:59.520 --> 00:08:01.830
All right, but now what happens

157
00:08:01.830 --> 00:08:05.130
when the getTasks function finishes execution

158
00:08:05.130 --> 00:08:08.850
and its context pops of the stack?

159
00:08:08.850 --> 00:08:13.260
Well, let's simulate that our garbage collection runs again.

160
00:08:13.260 --> 00:08:15.990
And again, I want to just emphasize

161
00:08:15.990 --> 00:08:18.030
that there is no way to control

162
00:08:18.030 --> 00:08:22.110
or trigger garbage collection manually from our code.

163
00:08:22.110 --> 00:08:24.690
We also have no way of knowing when

164
00:08:24.690 --> 00:08:27.600
and how often garbage collection happens.

165
00:08:27.600 --> 00:08:30.000
It depends on a few factors like

166
00:08:30.000 --> 00:08:32.250
how much memory our app is consuming,

167
00:08:32.250 --> 00:08:34.290
how much memory is available,

168
00:08:34.290 --> 00:08:38.790
which JavaScript engine the browser is using, and so on.

169
00:08:38.790 --> 00:08:41.970
But anyway, for the sake of this example,

170
00:08:41.970 --> 00:08:44.130
let's say the garbage collection algorithm

171
00:08:44.130 --> 00:08:46.860
runs again at this point.

172
00:08:46.860 --> 00:08:50.520
So now with the getTasks variable environment gone,

173
00:08:50.520 --> 00:08:51.810
there's really no one

174
00:08:51.810 --> 00:08:55.500
to reference the green object anymore, right?

175
00:08:55.500 --> 00:08:59.079
Therefore, the green object and also the blue object

176
00:08:59.079 --> 00:09:02.430
are no longer reachable from any root.

177
00:09:02.430 --> 00:09:04.800
They are no longer alive.

178
00:09:04.800 --> 00:09:08.310
Therefore, as the process moves into the sweep face,

179
00:09:08.310 --> 00:09:12.150
both the green and the blue objects will be swept away

180
00:09:12.150 --> 00:09:15.960
and the memory that they occupied will be reclaimed.

181
00:09:15.960 --> 00:09:20.220
Okay, but now let's turn our attention to the red object,

182
00:09:20.220 --> 00:09:22.560
and let's ask ourselves the question,

183
00:09:22.560 --> 00:09:26.220
how could this object ever be deleted?

184
00:09:26.220 --> 00:09:29.130
Well, the answer is that it can't.

185
00:09:29.130 --> 00:09:31.890
The red object will never be deleted,

186
00:09:31.890 --> 00:09:33.960
so it will stay in the heap forever

187
00:09:33.960 --> 00:09:37.920
because the global execution context will never disappear.

188
00:09:37.920 --> 00:09:40.350
So this root will always exist

189
00:09:40.350 --> 00:09:43.950
and we'll always be able to reach the red object.

190
00:09:43.950 --> 00:09:46.800
This means that any globally defined object

191
00:09:46.800 --> 00:09:49.080
will never be garbage collected,

192
00:09:49.080 --> 00:09:52.350
even if we no longer need it in our code.

193
00:09:52.350 --> 00:09:55.590
And what about the purple and yellow objects?

194
00:09:55.590 --> 00:09:59.730
What if our app also no longer needs those objects?

195
00:09:59.730 --> 00:10:03.330
Well, this idea of an object being no longer needed

196
00:10:03.330 --> 00:10:06.630
actually brings us to our final topic of this lecture,

197
00:10:06.630 --> 00:10:08.463
which is memory leaks.

198
00:10:09.330 --> 00:10:11.610
A memory leak happens when an object

199
00:10:11.610 --> 00:10:15.180
that is actually no longer needed by our application

200
00:10:15.180 --> 00:10:19.500
is incorrectly still reachable by the garbage collector

201
00:10:19.500 --> 00:10:21.690
from one of the roots.

202
00:10:21.690 --> 00:10:24.900
As a result, the object is marked as alive

203
00:10:24.900 --> 00:10:27.390
and is not deleted, again,

204
00:10:27.390 --> 00:10:31.020
even though we actually no longer need it in our code.

205
00:10:31.020 --> 00:10:34.440
So it should be deleted, but it can't.

206
00:10:34.440 --> 00:10:36.930
And you can think of a memory leak

207
00:10:36.930 --> 00:10:39.510
basically like forgetting to throw away

208
00:10:39.510 --> 00:10:41.910
some stuff that you no longer need.

209
00:10:41.910 --> 00:10:45.660
And so this will then clutter up your house unnecessarily.

210
00:10:45.660 --> 00:10:49.620
But back to JavaScript, this happens when an object

211
00:10:49.620 --> 00:10:53.100
is still incorrectly referenced from somewhere.

212
00:10:53.100 --> 00:10:55.470
And one major source of these wrong

213
00:10:55.470 --> 00:10:57.960
and undesired references are old

214
00:10:57.960 --> 00:11:01.650
and unnecessary event listeners and timers.

215
00:11:01.650 --> 00:11:04.890
If, for example, a timer creates an object,

216
00:11:04.890 --> 00:11:07.560
this object will always be reachable

217
00:11:07.560 --> 00:11:10.770
unless the developer actively deletes the timer

218
00:11:10.770 --> 00:11:12.870
when they no longer need it.

219
00:11:12.870 --> 00:11:15.690
Otherwise, if the timer just stays around

220
00:11:15.690 --> 00:11:18.720
and keeps running, it will forever reference

221
00:11:18.720 --> 00:11:22.530
the unnecessary object, causing a memory leak.

222
00:11:22.530 --> 00:11:24.630
The same is true for an event listener

223
00:11:24.630 --> 00:11:28.200
that might no longer be needed at some point.

224
00:11:28.200 --> 00:11:30.540
So in order to avoid memory leaks,

225
00:11:30.540 --> 00:11:33.060
make sure to always deactivate timers

226
00:11:33.060 --> 00:11:36.420
and event listeners when they're no longer required,

227
00:11:36.420 --> 00:11:39.930
especially if they reference large objects.

228
00:11:39.930 --> 00:11:44.010
Also avoid declaring large objects as global objects,

229
00:11:44.010 --> 00:11:47.190
because these will also never be garbage collected,

230
00:11:47.190 --> 00:11:48.690
as we just saw earlier.

231
00:11:48.690 --> 00:11:52.560
So that's gonna lead to memory leaks as well.

232
00:11:52.560 --> 00:11:56.730
Now, memory leaks can be a huge topic, but there's no need

233
00:11:56.730 --> 00:11:59.763
to dig even deeper into it at this point.

234
00:12:02.070 --> 00:12:03.930
This is a brief overview of

235
00:12:03.930 --> 00:12:06.630
how the garbage collection process works.

236
00:12:06.630 --> 00:12:10.200
It's gonna run over and over inside the user's browser

237
00:12:10.200 --> 00:12:12.090
while they're using the application,

238
00:12:12.090 --> 00:12:15.390
making sure that memory stays clean and uncluttered

239
00:12:15.390 --> 00:12:19.230
of objects that are no longer necessary over time.

240
00:12:19.230 --> 00:12:21.660
Now, in reality, memory management

241
00:12:21.660 --> 00:12:24.330
is way more complex than just this.

242
00:12:24.330 --> 00:12:27.300
It's an extremely complicated process.

243
00:12:27.300 --> 00:12:29.430
There are actually multiple heaps,

244
00:12:29.430 --> 00:12:31.530
objects are moved from one heap

245
00:12:31.530 --> 00:12:33.720
to another depending on their age,

246
00:12:33.720 --> 00:12:36.780
the garbage collector has multiple algorithms

247
00:12:36.780 --> 00:12:40.500
for the different heaps like generational garbage collection

248
00:12:40.500 --> 00:12:44.220
and so on, but I'm absolutely sure

249
00:12:44.220 --> 00:12:47.340
that this broad overview that you just learned about

250
00:12:47.340 --> 00:12:49.830
is more than enough at this point.

251
00:12:49.830 --> 00:12:53.250
So this already gives you a great idea of how memory

252
00:12:53.250 --> 00:12:56.553
is automatically managed inside the engine.

253
00:12:57.540 --> 00:12:59.670
And now before we move on, I need

254
00:12:59.670 --> 00:13:02.490
to quickly mention four more big topics

255
00:13:02.490 --> 00:13:05.120
about how JavaScript works behind the scenes

256
00:13:05.120 --> 00:13:07.500
that are not in this section

257
00:13:07.500 --> 00:13:10.980
but closer to where we actually need to learn about them.

258
00:13:10.980 --> 00:13:13.380
The first one, which I actually just mentioned

259
00:13:13.380 --> 00:13:15.873
in the last slide, is closures.

260
00:13:16.710 --> 00:13:19.110
We're gonna dive really deep into closures

261
00:13:19.110 --> 00:13:23.550
once we reach the Closer Look at Functions section.

262
00:13:23.550 --> 00:13:26.460
Next, one of the most fundamental concepts

263
00:13:26.460 --> 00:13:29.880
of JavaScript is prototypal inheritance,

264
00:13:29.880 --> 00:13:31.710
but we're only gonna talk about that

265
00:13:31.710 --> 00:13:35.460
in the Object Oriented Programming section of this course

266
00:13:35.460 --> 00:13:38.730
because it doesn't make sense to learn about this now

267
00:13:38.730 --> 00:13:43.200
only to forget it all until we finally reach that section.

268
00:13:43.200 --> 00:13:47.820
The same is true for a detailed lecture on the event loop.

269
00:13:47.820 --> 00:13:51.090
We already introduced the event loop in this section,

270
00:13:51.090 --> 00:13:53.880
but in section Asynchronous JavaScript,

271
00:13:53.880 --> 00:13:55.590
we'll dive really deep into

272
00:13:55.590 --> 00:13:58.020
how exactly this event loop works

273
00:13:58.020 --> 00:14:00.690
and why it's such a fundamental piece

274
00:14:00.690 --> 00:14:02.910
of the JavaScript engine.

275
00:14:02.910 --> 00:14:05.160
Finally, we'll have a few lectures on

276
00:14:05.160 --> 00:14:08.145
how the DOM actually works behind the scenes

277
00:14:08.145 --> 00:14:11.280
in the Advanced DOM and Events section as well

278
00:14:11.280 --> 00:14:14.910
so that you can then apply what you learn right away.

279
00:14:14.910 --> 00:14:18.630
And with this, we actually finished this huge section about

280
00:14:18.630 --> 00:14:22.230
how JavaScript actually works behind the scenes.

281
00:14:22.230 --> 00:14:26.850
It was a pretty long one with so many new concepts to learn,

282
00:14:26.850 --> 00:14:30.390
and many of them were hard and probably confusing,

283
00:14:30.390 --> 00:14:33.630
but again, that's really not a problem.

284
00:14:33.630 --> 00:14:37.830
Hard and confusing concepts are always a part of learning,

285
00:14:37.830 --> 00:14:41.730
and even if you did not understand 100% of everything,

286
00:14:41.730 --> 00:14:43.950
you're still good to move on in the course

287
00:14:43.950 --> 00:14:45.870
to the next section now.

288
00:14:45.870 --> 00:14:48.480
Just reaching the end of this section

289
00:14:48.480 --> 00:14:50.730
already gives you a huge advantage

290
00:14:50.730 --> 00:14:54.180
over many other developers who have no idea

291
00:14:54.180 --> 00:14:57.690
about many of the things that I just showed you here.

292
00:14:57.690 --> 00:15:01.050
So congratulations for sticking with it to the end

293
00:15:01.050 --> 00:15:04.200
and for learning all of this valuable knowledge.

294
00:15:04.200 --> 00:15:06.390
And now with that, take a break

295
00:15:06.390 --> 00:15:08.853
and I'll see you in the next section.

