Introduction To Dart Memory Management

mobile academy

Introduction To Dart Memory Management. In the previous post we learned about Dart Virtual Machine and Garbage Collection and in this post let us understand the basic concept on Memory Management in Dart / Flutter. To build any performant app it is crucial to understand how Memory are managed inside you app, it will help you to optimize your app performance.

Introduction To Dart Memory Management

As we have learned in our previous post Introduction to Garbage Collection, Dart automatically manage memory for use using Garbage Collection, unlike other programming C, C++ where the developer have to manage memory allocate or deallocate manually. Even though Dart automatically manages the Memory it is crucial to understand how it works to build a efficient and performative app failing to do so can lead to a Memory Leak in your are app which in return can will lead to slow and buggy app.

How Dart Allocates Memory

Dart objects created using a class constructor (for example, by using MyClass()) live in a portion of memory called the heap. The memory in the heap is managed by the Dart VM (virtual machine). The Dart VM allocates memory for the object at the moment of the object creation, and releases (or deallocates) the memory when the object is no longer used

Here’s a simple example:

Object Types

Disposable object

A disposable object refers to an object that implements the Disposable pattern or a similar mechanism in order to release any resources it holds, such as file handles, network connections, database connections etc.

The purpose of the disposable pattern is to ensure that resources are properly released and not held indefinitely, preventing resource leaks which can cause a memory leak.

In Dart / Flutter, the disposable pattern is typically implemented by defining a dispose() method on the object. When you are done using the object and want to release its resources, you explicitly call the dispose() method.

Here’s an example of a disposable object in Dart:

abstract class Disposable { 
  void dispose(); 
} 
class MyDisposableObject implements Disposable { 
  // ... implementation of the object 
  @override void dispose() { 
    // Release any resources held by the object // ... 
  } 
} 
// Usage: 
void main() {
  MyDisposableObject myObject = MyDisposableObject(); 
  // Use the object... 
  // Dispose of the object when it is no longer needed 
  myObject.dispose(); 
}

Here is also a dart package that we can use to implement Disposable.
w_common | Dart Package

Memory-risky object

A memory-risky object refers to an object that can potentially consume a significant amount of memory or cause memory-related issues in a program if not managed properly.

Root Object

Every Dart application creates a root object that references, directly or indirectly, all other objects the application allocates.

These are special objects that are always accessible and could never get deleted by GC. Examples include global variables and static fields. By being an anchor point in memory, they serve as the starting point for GC to track other objects. The GC starts from the root object and track every object that’s reachable from it.

Retaining Path

The retaining path is the path from the root object that leads to a certain object. It’s a chain of pointers which starts at a root object and ends at the desired object. Any object that has a retaining path from root is considered as ‘reachable’ and won’t be cleaned up by GC.

Reachability Path

An object is said to be ‘reachable’ if there’s a way to reach it starting from a root object, or in other words, if it has a retaining path. If an object is unreachable (has no retaining paths), it implies that the program can no longer access it. Hence, GC can safely deallocate memory occupied by it.

Here’s a simple example:

Shallow size

Shallow size refers to the memory consumed by an object itself, without taking into account any objects it references. It represents the direct memory usage of the object, including its own fields or properties. Shallow size provides an estimate of the memory required to store the object without considering any additional memory usage caused by referenced objects.

Retained size

Retained size, on the other hand, refers to the memory consumed by an object and all the objects that are still reachable from it, directly or indirectly. It takes into account not only the shallow size of the object but also the memory usage of all the objects it references. Retained size provides a more comprehensive measure of memory usage, accounting for all objects that are retained and cannot be garbage-collected.

Here’s a simple example:

In this example, child1 and child2 are both shallow memory allocations, each contains an object of Child holding only their own property (name).

In this case, parent is a retained memory allocation. It contains the Person object, which includes its own properties (name and children) and the objects it references (child1 and child2).

FAQ

1. Is the instance variable memory allocated in Stack or Heap?

In Dart language, instance variables are stored in the heap.

Each object, including all of its instance variables, occupies a memory area on the heap. When you create an instance of a class, memory is allocated on the heap for a new object, and a reference to that object is returned.

Values in the heap can be accessed by any part of your application and live beyond the scope of the function they were created in, persisting for as long as there’s some part of your application holding a reference to them.

In contrast, the stack is used for static memory allocation and stores temporary information such as function call information, local primitive types and reference variables. However, the actual objects these reference variable point to would be stored in the heap.

Therefore, if you create an instance of an object – the reference to this object is stored in the stack, while the actual object and its instance variables are stored in the heap.

2. Is the static variable memory allocated in Stack or Heap?

In Dart, static variables are stored in the heap, not the stack.

A static variable is essentially bound to a class, rather than an instance of the class. It exists from the time the class is loaded until the application is terminated. Therefore, the memory allocated for static variables is available for the entire duration of the application, which is consistent with the behavior of heap-allocated memory.

Become a Job Ready Flutter developer

https://mobileacademy.io/courses/

1 thoughts on “Introduction To Dart Memory Management

  1. Pingback: Memory Leak In Dart/Flutter - Mobile Academy

Comments are closed.

Select your currency
USD United States (US) dollar