Variable’s memory size in Python

Variable's Memory Size In Python

This article will explore the memory size of various data types in different Python versions. Additionally, we’ll learn how to determine the memory size of an object and its in-built data type. So, let’s dive in!

What is a variable?

A variable is a named memory block, which means it is a section of memory that can be accessed using a predetermined name. In low-level programming languages, a variable must have its data type defined, as different data types require varying amounts of memory. However, Python is an interpreted language, so we don’t need to specify the data type of variables when declaring them explicitly.

What is a data type?

A data type is a constraint on a variable. It specifies the domain of the value it contains. So, for example, the variable whose data type is a float will contain a decimal value. The variable whose data type is int will contain an integer value. The variable whose data type is char will contain a character only. Every variable has a data type. In Python, we don’t have to specify the data type at the time of declaration. Python interprets the data type of a variable by itself.

Every data type takes a fixed amount of memory size only. But how much memory size a particular data type would take differs for each data type. It even varies in each language. It also depends on the system you use. In Python, it also depends on the implementation of Python you use.

In this article, we will focus on the variable’s memory size in the most commonly used implementation of Python, which is CPython. We won’t be considering different implementations of Python like IronPython or Jython.

Related: Learn more about data types in Python.

How to check a variable’s memory size in Python?

To check a variable’s memory size in Python, we have a function called getsizeof() in the sys library of Python. This getsizeof function gives us the number of bytes of memory space consumed by a specific variable. It’s straightforward to use it.

Let’s check the size of variables of different data types using this getsizeof function.

Integer Variable

import sys
integer = 10
print("The size of the integer variable is:",sys.getsizeof(integer), "bytes.")

OUTPUT
The size of the integer variable is: 28 bytes.

In the above block of code, first, we imported the sys library. This sys library has the getsizeof() function we will use to get the size of the variable. Then we created an integer variable and initialized it with 10.

So, the size of the integer variable came out to be 28 bytes. Note that this size can differ on every system. But if you are familiar with C language, the size of an integer variable in C is 4 bytes. Why the big difference? 28 is the memory size consumed by the entire object on this particular system.

In general, integer variables in Python consumes a memory space of 4 bytes on a 32-bit system and 8 bytes on a 64-bit system.

Float Variable

import sys
decimal = 10.01
print("The size of float variable is:",sys.getsizeof(decimal),"bytes.")

OUTPUT
The size of the integer variable is: 24 bytes.

So floating values in Python take up a total memory space of 24 bytes. A floating value will take up the same amount of space no matter how big the value is, while a bigger integer will take up more space than a smaller integer.

String Variable

What is a string?

There’s no char data type in Python, like many low-level languages. In Python, we have the string variable. A string is an array of characters. It is a derived data type. Measuring the memory consumption of a string can be tricky. Let’s check the space consumed by this string data type.

First, let’s check how much space an empty string takes.

Empty string

string = ""
print("The size of the empty string is:",sys.getsizeof(string),"bytes.")

OUTPUT
The size of the empty string is: 49 bytes.

So, an empty string takes 49 bytes of memory space. It’s crazy how much space a single character would take in Python.

Single character

string = "a"
print("The size of a single is:",sys.getsizeof(string),"bytes.")

OUTPUT
The size of a single character is: 50 bytes.

So the size of a single character in Python is 50 bytes. A single character in C consumes a memory space of 1 byte. So storing a single character in Python takes 50 times more space than storing a single character in C. Compared to the empty string, a single character took only 1 extra byte of memory space.

Before we jump to any conclusion, let’s check how much space a string of 2 characters takes.

String of two characters

string = "ab"
print("The size of a string of two characters is:",sys.getsizeof(string),"bytes.")

OUTPUT
The size of a string of two characters is: 51 bytes.

Okay, a string of two characters takes up 51 bytes of memory space. So that means an empty string takes up 49 bytes of memory space, and for each character, 1 extra byte is required.

Why does an empty string take up so much space?

A string is an object in Python. It is an array of characters. Python provides a lot of functionalities for strings. For that, Python takes up all this space. Python for sure takes a lot of space to store a string, but at the same time, the amount of flexibility Python provides is a good trade-off for run time.

Now that we have checked the memory consumption of all these basic data types, let’s check the memory consumption of lists, tuples, dictionaries, etc.

Memory space consumed by a List

import sys
list_ = []
print("The size of the empty list is:",sys.getsizeof(list_),"bytes.")
for i in range(10):
    list_.append(0)
    print("The size of the empty list is:",sys.getsizeof(list_),"bytes.")
Code And Output For Checking Memory Usage Of A List
Code And Output For Checking Memory Usage Of A List

In the above code, first, we checked the size of an empty list. An empty list takes up 56 bytes of space. Then as soon as we add an element, the size of the list increases by 32 bytes. Then the size remains stagnant till 4 elements are added. For the 5th element, it again increases the size by 32 bytes. So the list takes up 56 bytes of overhead. That’s a lot of space. That means every time we create a list, it takes an extra 56 bytes of memory space.

Note that the memory usage will be only 8 bytes for each element in the list, no matter how much space the element takes. This is because a list doesn’t store the element; it stores the pointer to the element.

Related: Learn lists in Python in depth.

Memory space consumed by a Tuple

import sys
tuple_ = ()
print("The size of the empty tuple is:",sys.getsizeof(tuple_),"bytes.")
tuple_ = (0,)
print("The size of the tuple with 1 element is:",sys.getsizeof(tuple_),"bytes.")
tuple_ = (0,0,)
print("The size of the tuple with 2 elements is:",sys.getsizeof(tuple_),"bytes.")
tuple_ = (0,0,0,)
print("The size of the tuple with 3 element is:",sys.getsizeof(tuple_),"bytes.")
Code And Output For Memory Usage Of A Tuple
Code And Output For Memory Usage Of A Tuple

In the above code, first, we checked the size of an empty tuple. An empty tuple takes up 40 bytes of space. Then we added an element. The size of the tuple increases by 8 bytes. Then for each element, we add the size of the tuple increases by 8. Again, for each element in the tuple, the memory usage will be only 8 bytes, no matter how much space the element takes. This is because a tuple doesn’t store the element; it stores the pointer to the element.

Memory space consumed by a Set

import sys
set_ = set()
print("The size of the empty set is:",sys.getsizeof(set_),"bytes.")
for i in range(10):
    set_.add(i)
    print(f"The size of the set with {i+1} element is:",sys.getsizeof(set_),"bytes.")
Code And Output To Heck Memory Usafe Of A Set
Code And Output To Heck Memory size Of A Set

The set has a memory overhead of 216 bytes. And then adds 512 bytes each time when the set fills up. The set is fast but consumes a lot of memory space.

Memory space consumed by a Dictionary

import sys
dict_ = dict()
print("The size of the empty dictionary is:",sys.getsizeof(dict_),"bytes.")
for i in range(10):
    dict_[i]=i
    print(f"The size of the set with {i+1} element is:",sys.getsizeof(dict_),"bytes.")
Code And Output For Checking Memory Usage Of A Dictionary
Code And Output For Checking Memory Usage Of A Dictionary

The set has a memory overhead of 232 bytes. And then adds 128 bytes each time when the set fills up. The set is fast but consumes a lot of memory space.

deep_getsizeof

Checking the total memory usage by an object or a data structure like a list, tuple, or set can be tricky as it may have lists, tuples, or nested objects that don’t get added in getsizeof function. To check an object’s total memory usage, we use the deep_getsizeof method. In this method, we recursively call the getsizeof function for every part of the object. Let’s see how the function goes.

import sys
def deepgso(ob):
    size = sys.getsizeof(ob)
    if isinstance(ob, (list,tuple,set)):
        for element in ob:
            size+=deepgso(element)
    if isinstance(ob, dict):
        for k,v in ob.items():
            size+=deepgso(k)
            size+=deepgso(v)
    return size

First, we declare the function. In the function, we create a variable size. We add the size of the object as per the getsizeof function. Then for each element in the object, we run the getsizeof function on it. The size of each element is added to the size variable. Finally, we return the size variable, which stores the total size of the object.

Let’s test the function.

list_=[[1],1,"1"]
print("Space consumed by the list using getsizeof:",sys.getsizeof(list_))
print("Total space consumed by the list:",deepgso(list_))

OUTPUT
Space consumed by the list using getsizeof: 80
Total space consumed by the list: 250

We took a list of a list with one element, an integer, and a string with a single character. Using the getsizeof function, we get the size as 80 bytes. 56 as the overhead and 8 for each element. We know that this is just the space consumed by the list. The elements inside the list are not included. So to include the elements inside the list, too, we used the deep_getsizeof function we created. Using that, we get a total space of 250 bytes.

Memory leaks in Python

Memory leaks are a big problem in Python and all programming languages. But the problem is severe in Python as variables in Python take up too much space. To avoid memory leakage in Python, we use an in-built module called tracemalloc. Tracemalloc can be used to check the program’s memory consumption and take measures against memory leakage. To check the memory consumption by a program, we can use the get_traced_memory function. It returns two values, current memory consumption of the program and peak memory consumption of the program.

To avoid memory leakage, we can use the start function of tracemalloc at the beginning of the program and then the stop function of tracemalloc at the end. This will free up all the used memory in the program each time.

Conclusion

Variables in Python take up too much space. Python is no doubt an awesome language. The amount of functionality Python provides is not available in any other language. But the memory consumption in Python is very high. This makes Python a bad choice in a place where you have memory constraints. We also need to make sure that there is no memory leakage in our program. Always remember to free up the space used up by the program.

References

Official Python Documentation

Stack Overflow answer for the same question.