The memory method in Python refers to the sys.getsizeof()
function, which provides the size of an object in bytes. This helps developers understand how much memory an object consumes.
Memory management in Python is key to ensuring programs run smoothly and don’t use extra memory than needed. Python handles most of the memory work automatically. However, it’s still important to understand how Python uses memory, so we can write better and more efficient programs.
Key takeaways:
Memory allocation: Python uses two methods for memory allocation:
Static memory allocation (stack memory) is fixed and persists for the program’s duration.
Dynamic memory allocation (heap memory) is flexible and reusable during program execution.
Garbage collection: Python’s garbage collector automatically handles memory deallocation. It works by releasing memory when the reference count of objects reaches zero.
Best practices:
Avoid unnecessary list slicing and indexing.
Be cautious with string concatenation due to the immutability of strings.
Use iterators and generators for memory-efficient data processing.
Leverage built-in libraries for optimized performance.
Space reduction: Implementing efficient memory management practices can significantly improve program performance and reduce space complexity.
In simple terms, memory management in Python refers to how Python handles storing and freeing up memory while a program runs. Whenever you create a new object (like a variable or a list), Python needs to find space in memory to store it. When the object is no longer needed, Python frees up the memory to be used by something else.
When Python runs a program, it uses two main ways to allocate memory:
Static memory allocation
Dynamic memory allocation
The stack data structure provides static memory allocation, meaning the variables are in the stack memory. Statically assigned variables, as the name implies, are permanent; this means that they must be allocated in advance and persist for the duration of the program. Another point to remember is that we cannot reuse the memory allocated in the stack memory. Therefore, memory reusability is not possible.
x = 20y = []z = ""
The dynamic memory allocation uses heap data structures in its implementation, implying that variables are in the heap memory. As the name suggests, dynamically allocated variables are not permanent and can be changed while a program is running. Additionally, allotted memory can be relinquished and reused. However, it takes longer to complete because dynamic memory allocation occurs during program execution. Furthermore, after utilizing the allocated memory, we must release it. Otherwise, problems such as memory leaks might arise.
x = [0]*5 #This memory for 5 integers is allocated on heap.
The Python garbage collector handles memory allocation and deallocation automatically. Python developers designed it to eliminate the need for manual garbage collection. Garbage collection in Python refers to the interpreter’s memory management process of freeing up unneeded and undesired memory for our applications.
Note: Python uses garbage collection to release memory blocks no longer in use.
The garbage collector (GC) operates in the background and is triggered when the reference count reaches zero.
The reference count rises when the following occur:
An object is given a new name
An object is placed in a container, such as a tuple or a dictionary
The reference count lowers when the following occurs:
An object’s reference is reassigned
An object’s reference moves out of scope
An object is removed
Memory is a heap that stores the program’s objects and other data structures. The Python memory manager uses API methods to allocate and deallocate this heap space.
Let’s see a basic example of how it works:
class Test(object):passx = Test()x.obj = xdel x
We create a new Class
in the example above. After that, we created an instance of the class and made it a property of itself. Finally, we remove the instance from the system. The instance is no longer available in our Python application when we delete it.
Let’s see how to use the gc
module in Python:
import gcprint(gc.get_threshold())
As we can see, we import the gc
module and print the garbage collection thresholds. From the output, Python has a threshold of 700 for the youngest generation and 10 for each two older generations by default.
We may use the get_count()
method to get the number of objects in each of our generations:
import gcprint(gc.get_count())
The gc.collect()
method returns the number of collected and deallocated items.
import gcprint(gc.collect())
The set_threshold()
method allows us to change the garbage collection thresholds.
import gcgc.get_threshold()gc.set_threshold(7777, 11, 11)print(gc.get_threshold())
Here are some common practices to improve memory management in Python:
When we slice a list in Python to get a sublist, Python creates a copy of the data. This is fine for small lists but can use a lot of memory with larger data.
Instead of slicing, we can track indexes with a variable to avoid copying large portions of the list and reduce memory use.
If we don’t need to use list indexing, it’s better to avoid it. For example, instead of writing:
for item in array:
We can use the following:
for index in range(len(array)):
This saves both time and space, especially when working with large lists.
Strings in Python are immutable, meaning when we add two strings together with +
, Python creates a new string in memory. This can be slow and use extra memory if done repeatedly.
For example, instead of writing:
a = "Mango"a = a + " Ice-cream"
We can use the following:
a = "".join([a, " Ice-cream"])
Or we can use format()
or %
to combine strings efficiently.
When working with large datasets, using iterators and generators can save a lot of memory. Iterators fetch one element at a time and generators yield values on the go, avoiding loading the entire dataset into memory.
Example of using a generator:
def _generator(self):for i in self.items():yield i
Generators process data only when needed, making them great for memory-efficient loops.
Whenever possible, use Python’s built-in libraries. These are optimized for performance and memory use, saving space and time. For example, instead of writing your own functions for common tasks, use the libraries provided by Python to avoid unnecessary memory overhead.
By following these simple practices, you can significantly improve memory management in Python and reduce the space complexity of your programs.
Ready to deepen your Python knowledge? Start our "Become a Python Developer" Skill Path, which begins with Python’s basic concepts and advances to more complex topics, preparing you for a career as a Python developer.
Haven’t found what you were looking for? Contact Us