Types of memory in swift

How to understand types of memory: A Tutorial. The difference between heap and stack, their advantages and disadvantages.

Timur Cheberda
5 min readApr 22, 2022

Static — Allocates memory before starting the program itself. The type of such memory is available for the entire duration of the program. In most cases, in programming languages, when placing an object in static memory, you only need to declare it in the global scope. It applies to global variables, file scope variables, and variables qualified with static defined inside functions.Placed on a separate memory segment.

Automatic — Memory view, which is also known as “stack placement,” is the most basic view. It automatically allocates various arguments and local variables of the function, as well as other different meta-information when calling the necessary functions, and then it frees up memory when exiting it.
int a = 43;

Dynamic — Allocating memory from the OS at the request of the application, as an example — a bunch.
int * a = malloc(sizeof(int)); Heap memory is persistent until free() is called. In other words, you control the lifetime of the variable.

Stack.
The data type — value type, works on the LIFO principle — Last In First Out.

  1. Structs
  2. Enums ( but not indirect enums )
  3. Tuples
  4. Protocols
  5. Primitives (integer, bool, float, double and etc )
  • It grows towards a decrease in addresses, that is, its beginning is somewhere in the older addresses, and its end is somewhere in the younger addresses.
  • It is controlled and optimized from the CPU and allocated during compilation.
  • Always copied when assigned and each thread has its own stack.

For the simplicity of the picture, suppose that each stack has a variable (stack pointer) — the address of the most recent added element. It is used to track the vertex of the stack and stores an integer number (Integer).
Another pointer is base pointer — the address of the beginning of the frame, from which values are entered or extracted into the stack, it is used to obtain parameters in the stack, since its address is always static, unlike stack pointer.
There are 2 main commands for working with the stack:
Push — put the data on top of the stack, thereby increasing the stack ponter.
Pop — extract data from the top of the stack, thereby reducing stack pointer.

Stack Operations:

  • Inclusion
  • Exception
  • Sizing
  • Cleaning
  • Non-destructive reading

Each function in the stack has its own place, which is called the memory frame, inside there is the local environment of the function in the form of its variables.

Heap
The data type — reference type, a tree-like data structure where memory is allocated from the OS at the request of the application, used for dynamic memory allocation and allotted during program operation (runtime). After allocating memory, the program receives a pointer to the beginning of the allocated memory. The heap common to all application threads.
All data in the heap is arranged linearly, that is, from the beginning of its memory to its end, towards an increase in addresses.

  1. Classes
  2. Functions
  3. Indirect Enums
  4. Actors

Classes and structures can:

  • Define a property to store values.
  • Define methods and functions.
  • Implement protocols.
  • Define initializer.
  • Define subscripts to allow access to their variables.

Only classes can:

  • Implement inheritance.
  • Type conversion.
  • Define a deinitsializator.
  • Counting links.

To summarize the difference between structures and classes, you need to understand the difference between values and reference types.

  1. When you copy a value type, all data is copied from the copied object to the new variable. They are two separate objects, and changing one does not affect the other.
  2. When you create a copy of a reference type, the new variable references the same memory location as the object being copied. This means that changing one of them will change the other, since both belong to the same location in memory.
Difference between value and reference type

What does Apple advise?

  1. Use structures by default.
  2. Use classes if you want to interact with Objective-C.
  3. Use classes if you want to control the identification of simulated data.
  4. Use structures along with protocols to use behavior by sharing implementations.
  5. Use structures to avoid: reference count, administration of free memory and its search for allocation, overwrite memory for de-allocation.

An important addition!

Assigning reference types to stack the swift compiler can promote reference types for stacking when their size is fixed or the lifetime can be predicted. The Swift compiler can package value types and place them in a heap:

  • Subject to the protocol. In addition to provisioning costs, additional overhead occurs when the value type is stored in an existential container * and exceeds the length of 3 machine words.
  • When mixing value and reference types. Typically, a class reference is stored in a structure, and the structure is a class field:
  • Escaping closure if the value is stored on the stack and captured by the escaping closure, then this value is copied to the heap, thereby allowing it to be available before the closure is executed. This statement is only valid for escaping closure, since only it can be executed later.
  • Inout argument. The inout arguments are passed to the entry point at. The called object does not gain ownership of the specified memory. The specified memory must be initialized when entering and exiting the function. If the inout argument refers to unowned unsafe, so the argument is the address of the variable. If the inout argument refers to a boolean property, then the argument is the address of the write back buffer belonging to the caller.
  • String is a copy-on-write structure, to implement its dynamism, it stores all its characters on heap. Thus, string is a structure, and is stored in stack, but it stores all its content on heap.

*An existential container is a shared container for a value of an unknown runtime type. Small-sized value types can be embedded in an existential container. Larger ones are placed in a heap, and a reference to them is stored in the existential buffer of the container. The lifetime of such values is controlled by the value witness table. This introduces the overhead of reference counting and several levels of indirect handling when calling protocol methods.

Link:

--

--

Responses (1)