In our previous lessons, we have learnt
the concept of dynamic memory allocation. We have understood what is stack and what is
heap in applications memory. Now in this this
lesson, we're going to talk about one situation which has caused by improper use of dynamic memory or the memory on the heap and this
situation is memory leak. A quick recap of some of the concepts
that we have discussed in our previous lessons. The memory that is allocated for the
execution of an of of a program or what we can also
call applications memory is typically divided into these four
segments or these four sections. One section store stuff instructions in
the program that need to be executed this section is
called the code segment or the text segment, another section is use to
store the global variables, the variables which are declared inside functions and have
lifetime of the whole application. Another section of the memory is used to
execute the function calls and store all the local variables this
section is called stack. The size of these three segments the
code segment, the global variable segment, and the stack segment are fixed and decided when the program is
compiling and that is that the compile-time, and
the forth section which is quite heap or dynamic memory
does not have a fixed size. Heap can grow as per our need. As we know we get memory from the heap
by making the call to malloc function in C and when we are done using that memory
on the heap, we make a call to the free function to deallocate
or free that particular memory. In C++ apart from malloc and
free, we can also use the operater new to get some memory and
operater delete to free that memory. Leak is a
situation when we get to memory on the heap and do not
free it when we are done using it. So our application is actually holding on to some unused
memory on the heap but why do we call the situation memory leak and why does it happen due to improper
use of dynamic memory only, due to improper use
of heap only and not some other sections of applications memory.
We will try to understand this through one simple program so what I'll do is
I'll write one simple program and show the simulation of its execution in the
memory to explain these concepts. In my C program here, I'm going to write a
very simple betting game and the game is that we have three
positions and three cards Jack, queen and king Initially jack is at the first position.
Queen is at the second position and King is at the third position and then computer shuffles these cards so
that the positions of these cards is changed, is randomized and now the player has to guess the position of the
Queen. He has to bet some amount of money. Let's say it's a virtual cash and if
he win see if he predicts the position if I guess the position of
queen correctly, he takes over it three times the amount that he had bet and if he loses he simply loses the bet
amount. Let's say player initially has
hundred-dollar of virtual cash and he can me as many times as he wants and untill he runs out of cash. So let us
know implement this game the first thing that I want to do is I
wanted to declear a global variable named cash that at any point will
store the virtual cash available with the
player. Initially, he has hundred dollars of virtual cash and then
in the main method I will declare a variable name bet and have a great code something
like this. While cash is greater than zero, while player still
has some cash. We will ask him to bet something and we will it take this input in this
variable bet using scanf. For negative scenarios
like bet equals zero, bet being greater than the cash available,
we will break out of this loop. We will end our game. For all other conditions, let's say it
will make a call to play function, and of course now we will have to write
the play function. We will be passing bet to the play function, so bet will be an
argument. Now in a play function, i will declare a character J array of size 3 and initially, we will have the character at the
first position to say that there is jack at the first position.
J for jack and similarly Q is for Queen and
K is for king and now the computer must perform a
randomized shuffling. So we will write a print statement like
this. Now we need to find a logic to make a random shuffle of cards. One such logic is that we can make a
call to random number generator function in C. To use the random number generator
first we will make a call to srand function and pass it an argument something like this. I'll come back to
what I'm doing here in a srand by making a call to
srand and now let's say we run a loop five times and we will choose any two random positions among
0, 1 and 2 and swap the later said these positions
in the array. Let's say these positions are X&Y. Now
then we make a call to rand function we will get at random number but we want a number
between zero and 2, O and 2 included. So we will take modulo by 3 so that we either get 0 or 1 or 2 So we will take 2 such a random
positions, with statements like this and now what we can do is we can swap the
character at these positions. So we will use a temporary variable. First
we will store the character that position X
in temp and then we will do something
like this. I'm short of space here. I'm writing three
statements in the same line. Okay so now swapping is done.
104
00:06:08,710 --> 00:06:11,770
So we are swapping or shuffling characters at two positions, five times
each time we are picking up two positions X and Y randomly by making call to rand
function and taking a modulo by 3. So this will guarantee us that X and Y is
between 0 and 2 that will be valid positions. By
making a call to rand function, we will get the random numbers, but we also used this srand once and passed this time null the return of time function. In random number generation, there is
something is one concept of seeding the random
number generator, so we are passing seed to random number
generator. We will not go into the details of random number generation now. Now what I'll do in the play function
is i'll have a variable named players guess and I'll ask the player to guess the
position of Queen and then I will use scanf to take the
input. Now if the player is correct then the character at that particular
position in character array c and the position will be one minus what
the their inputs because the player is inputting
1, 2 or 3 that will map to 0, 1 and 2 in the array. So if the
character is queen he has won. So his overall cash will be incremented by three times the
bet amount else he has lost and his cash will be
decremented by the bet amount. So in the case of when we will write
a print statement like this. We will say that you have won and the
result is this and your total cash right now is this. Remember
cash is a global variable and we will print something similar if
the player loses. Finally our play function is looking
something like this and we have also moved this variable
cash at the top. In the main method, i have added two
more print statement initially. Let's now play this game and see what
happens. what I have done is I have compiled this code and created an
executable named game.exe and now I'm going to
run that executable. So this is asking what's your bet.
Let's say we want to bet five Dollars on position 1 and I lose on my balance now is ninety five dollars.
Let's bet again, this time again i lose and I can go on
playing. So i'm losing again and again. Finally a win after a longtime. I can go on playing this game but I want
to show you something else. I have opened the task manager of
Windows and here as you can see and this
highlighted row is for game.exe. The third
column here is the memory consumed by this executable
game.exe. You will have to see this in full screen. Now as I go on playing, the memory
consumption here the memory that showing here is not increasing.
It's always 348 k. Now I'll go ahead and make some
changes in my code. I'll do here is, this particular
character array that I'm creating as a local variable in the play function right now it's created as a local
variable , so it will go on the stack. I want to
create a character array on the heap. So what I'll do is I'll right statement like this, i'll declare
a character pointer named C and then I'll use malloc to fetch memory to store 3 character
variables. In C++, we could have said
something like this, we could have used the new operator and
now i'll set the values at
zeroth index as J, oneth as Q and twoth
as K. So we have created an array on the heap and C is a pointer to the base address of that array. C is still
a local variable but now it is a pointer to character and we can still use it like array. The rest of the code
will just work fine. Let us run this code and see what happens. I have opened the task manager and I'm
running the executable. Watch for the memory consumption of
game.exe. I will make some bets. As you can see
right now the memory consumption is 348k. I just kept on playing and after
some time the memory consumption is 488 K. It has shot up and if you will
keeping this game further after some time it will shoot up again.
Maybe after some time but it for shoot up for sure. So why is it
happening. Why was it not shooting up when C
the character array was not on not on the heap and it
was under stack. Let's try to understand. I have drawn sections of applications
memory here, and let us now see what really happens
in the memory when we are playing a game. As we know
from our previous lessons all the information about function
call execution goes into the stack section of the memory. Any
time the function is called are some amount of memory from the stack
is allocated for its execution. When the program starts executing first
the main method is invoked or called. So let's say some amount of memory is
allocated for the execution of main this is what we call the stack
frame of a function. So this is stack frame of main and all the
local variables of main will sit inside this stack frame in
our code we had a local variable named bet. So it will go here and we had a global
variable named cash. Initially let's say main
function is executing. When we play a game main function makes
multiple calls to play function. What really happens when a
function makes calls to another function is that. That particular function is
paused and memory is allocated for the execution of on the called function. So main will pause
and play even start executing and play will go on top of main
in the stack. We had a couple of local variables in
play all will go in this stack frame. I X Y players guess and for the case one when we had the
character array C on the stack itself, so it was not created using a call to
malloc by the character array C will also
sit in this stack frame. Now when the execution of play function
will finish, control will return back to main and a
memory that was allocated for the execution of play function will be
reclaimed. Any time function call finishes the
memory that it is allocated on the stack is reclaimed. So there is one stack frame
corresponding to each call and at soon as that call finishers that
memory is claimed back and now main will make
another call to play because we will play multiple rounds. So play will again come into the stack and
it will be cleared again when play finishes. As you can see all the local variables get
cleared each time the function call finishes. For anything on the stack we do not have
to worry about it's deallocation it happens automatically when the
function call finishes. Now let's talk about the second case when
character array is created on the heap using a call to malloc function. Once again we will make multiple calls to
play function. Now what will happen this time is
that we will not create the array on the stack. we will still
have are varaible named C, a local
variable named C. But this variable will not be of type
character array of size 3. This variable will be of type pointer to
character and we will make a call to malloc function
to create the array on the heap and this local variable which is a
pointer to character will only points to this particular memory block. Anything that is on the heap has to be
accessed through a pointer variable. So here we have created the array on the
heap and we have kept only a pointer variable on the stack. Now when the call to play function will
finish the memory allocated for the execution of call to play function will be reclaimed so all the local
variables will go away. But this memory on the heap the lie
unused and un referenced and it will not get deallocated.
Anything on the heap has to be explicitly deallocated by making the
call to free function or by using a delete operator and
think about it. We will make multiple cause to play function as we play multiple rounds of our game
and each time in each call we will
create one such memory block on the heap that will lie unreferenced and unused
when call to play function will finish. If we will play a game 100 rounds then they will have 100 such unreferenced
and unused memory blocks of 3 characters in the heap. heap is not fixed in size and our
application can claim can get more memory in the heap
section as long as our system itself is not
running out of memory and if we are not be allocating and
this unused memory on the heap, we are depleting and wasting memory which
is an important resource. Our applications memory consumption will
only keep on growing with time. Memory leaks are really nasty
bugs to have in your program. Anything unused and unreferenced under
heap is garbage. In C or C++ we have to make
sure as programmers that garbage is not
created on the heap. Memory leak is nothing but growth of
garbage in the heap. In languages like Java and C#, garbage automatically
cleared from the heap. So programmer does not have to worry about freeing or deallocating the memory
on heap which is a cool feature to have. It avoids memory leak. In this example, we
were creating an array of three characters on the heap, What if we were creating an array of
10,000 characters and not freeing the memory after we were done using
it. At the end of the function the memory consumption would have shot
up like anything. Coming back to my code here, what I have done is I have created a
character array of size ten thousand of ten thousand characters here. My
logic would not change. I'll just use first three positions in the
array. I'm just trying to show you something and ta end of this
particular function when we are done using this array on the heap. We are making
call to free function, passing it the address of this memory
block this array C. Our program will just work like before,
but let's from this and monitor the memory consumption once again. Once again I'm showing you that task
manager and I am playing the game let's make some bets. Now watch out
the memory consumption of game.exe. For howsoever long you will play the
game the memory consumption wont shoot up. As
you can see it's 356 K and it's not shooting up for me even after playing for a long time, and
it is not shooting up because we had used free to deallocate the memory when we were
done using it at the end of the function. Remember we had created an array of
size ten thousand and if we were not using free then the
memory would have shot up like anything. The memory consumption would
have shot up like anything. but because we are freeing at the end
of the function it's not going up there is no memory
leak. so finally to summarize it, memory leak is improper use of dynamic
memory or the heap section of memory that
causes the memory consumption of our program to increase over a period of time.
Remember memory leak always happens because of unused and unreferenced memory
blocks in the heap. Anything on the stack is deallocated automatically and
stack is all is fixed in size. At the most we can have an overflow
in stack. So this was memory leak in C C++. Thanks for watching.