About Program Memory, A Few Insights
About Program Memory: A Few Insights
Foreword: Recently, I have been studying pointers, which has led me to have a deeper interaction with memory. I realized that I had a blank slate regarding this area. Thus, I took the opportunity to learn a bit and wanted to share my reflections.
Introduction
1 |
|
The running result indicates: line 1 will cause an error, but line 2 will not.
Consider why this is the case?
Hint: They are stored in different areas, which means they are in different memory segments!
I hope this article can help you find the answer.
What is Memory Segmentation?
Here, we will discuss memory segmentation in the context of C language.
The diagram below illustrates the memory segmentation in C:
Stack Segment
Overview of the Stack Segment
- The stack segment is automatically allocated and freed by the compiler, and it is managed by the operating system, requiring no manual management.
- The content in the stack segment only exists within the scope of the function. Once the function ends, this content will also be automatically destroyed.
- The stack segment grows downwards in memory address from high to low, with its maximum size determined at compile time. It is fast but lacks flexibility and has limited space.
- The stack segment operates on a Last In, First Out (LIFO) principle, meaning the last item added is the first to be removed.
Content Stored
- Temporarily created local variables and local variables defined with
const
are stored in the stack segment. - When functions are called and return, their input parameters and return values are also stored in the stack segment.
Heap Segment
Overview of the Heap Segment
- The heap segment is allocated and freed by the programmer.
- The heap segment grows upwards in memory address from low to high, with its size determined by system memory or virtual memory limits. It is slower but more flexible, allowing for larger available space.
Function Calls
- Memory allocation in the heap is accomplished using functions like
malloc
.
1 | void *malloc(size_t); |
Parameter size_t
specifies the number of bytes to allocate.
Return value is a pointer of type void*
, which points to the beginning address of the allocated space.
(The void*
pointer can be cast to any other type of pointer.)
- Use the
free
function for memory deallocation, or it will cause memory leaks.
1 | void free(void * /*ptr*/); |
Parameter is the starting address of the allocated memory.
Global Static Segment
Overview of the Global Static Segment
- This segment is typically used for variables whose storage size can be determined during compilation. It is used for global variables and static variables that are visible throughout the entire program’s runtime.
- The global segment consists of the .bss and .data segments, which are readable and writable.
- The memory space is managed by the system: it is allocated when the program starts and reclaimed when the program ends, and it exists throughout the program’s execution!
.bss Segment
- Uninitialized global variables and uninitialized static variables are stored in the .bss segment.
- Global variables initialized to 0 and static variables initialized to 0 are also stored in the .bss segment.
- The .bss segment does not occupy space in the executable file; its content is initialized by the operating system.
.data Segment
- Initialized global variables are stored in the .data segment.
- Initialized static variables are stored in the .data segment.
- The .data segment occupies space in the executable file and is initialized by the program.
Supplement on static
The first and most important point is hiding:
- When compiling multiple files simultaneously, all global variables and functions without the
static
prefix have global visibility. - The
static
prefix can be applied to both functions and variables, limiting the function’s scope to the file it is defined in. - This feature allows defining functions and variables with the same names in different files without worrying about naming conflicts.
- When compiling multiple files simultaneously, all global variables and functions without the
The second function is to maintain the variable’s content persistently:
- Since
static
variables are stored in the global static segment, they persist throughout the program’s execution and are not released when the function ends. - The
static
keyword controls the variable’s scope, but ultimately, it is used for hiding. - This feature allows defining functions and variables with the same names in different functions without worrying about naming conflicts.
- Since
The third function is default initialization to 0:
- Global variables also have this property since they are stored in the static data segment.
- In the static data segment, all memory bytes are initialized to 0x00, which can sometimes reduce the programmer’s workload.
Constant Segment
- Strings, numbers, and other constants are stored in the constant segment.
- Initialized global variables.
- Initialized static variables.
- Global variables modified by
const
are stored in the constant segment. - The content of the constant segment cannot be modified during the program’s execution.
Code Segment
- The executable code of the program is stored in the code segment, and its content cannot be modified (modifying it will result in an error).
- String constants and constants defined by
#define
may also be stored in the code segment.
Supplementary Concepts
- Memory Leak: Refers to allocated memory space that has not been reclaimed after use.
While one instance of memory leak can be ignored, continual leakage, regardless of how much memory is available, will eventually occupy all memory and lead to the programcrashing
. (Thus, we should strive to avoid memory leaks in development.) - Out of Memory: Refers to a situation where a program cannot find sufficient memory space for its use when requesting memory.
In simpler terms, it means running out of memory. This often occurs when running large applications or games, where the memory needed far exceeds what is installed on the machine, leading to arestart
or programcrash
.
Returning to the Introduction
When we define an array, it is actually allocated in the global static segment or stack segment.
When we define a string pointer, it is actually allocated in the constant segment.
Thus, the final result is that the second type is non-modifiable!