Lecture Notes 04 (CSI2372 - Advanced Programming Concepts With C++)
Lecture Notes 04 (CSI2372 - Advanced Programming Concepts With C++)
Lecture Notes 04 (CSI2372 - Advanced Programming Concepts With C++)
1
CSI2372 - Advanced Programming Concepts with C++
Course Outline:
2
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
3
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
4
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
5
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.
Low-level memory access and assembly-level programming involve working closely with the physical memory of a
computer, typically at a level much closer to the hardware than most high-level programming languages.
Pointers play a crucial role in facilitating these low-level memory operations. To have a deep understanding of low-
level memory operations we need to know:
6
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.
7
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.
Assembly Language:
Assembly language is a low-level programming language that uses prompts to represent machine-level
instructions. Programmers use assembly language to control the computer's hardware directly, including memory
access.
Memory Operations with Pointers:
Pointers in C++ can be used to interact with assembly language routines, enabling direct memory access. This can
be useful for tasks like working with hardware devices, optimizing performance-critical code, or interfacing with
operating system functions.
8
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.
#include <iostream>
int main() {
int value = 200;
int* ptr1 = &value; // Pointer pointing to the memory address of 'value'
int* ptr2 = &value; // Pointer pointing to the memory address of 'value'
// Reading from memory location using the pointer
//std::cout << "Value at memory address " << ptr << ": " << *ptr << std::endl;
// Initialize the pointer with nullptr (no memory address)
int* new_ptr = nullptr;
ptr1 = new_ptr;// Change the pointer to point to the new memory
9
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.
if (ptr1 == nullptr)
{std::cout << "First pointer is null" << std::endl;}
else {std::cout << "First pointer " << ptr1 << ":" << *ptr1 << std::endl;}
if (ptr2 == nullptr)
{std::cout << "Second pointer is null" << std::endl;}
else {std::cout << "Second pointer " << ptr2 << ": " << *ptr2 << std::endl;}
return 0;}
10
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.
In the previous slide, we used a pointer (nullptr) to exchange the values between two addresses which
is essential for read and write the value at a specific memory address. This demonstrates the basic
concept of low-level memory access with pointers.
Keep in mind that low-level memory operations should be used with CAUTION, as incorrect memory
manipulation can lead to crashes and instability. These techniques are typically reserved for specialized
tasks and optimization, and they require a deep understanding of hardware and memory
management.
11
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Examining assembly language and memory manipulation.
12
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.
13
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.
❑ Kernel development in C++ is highly specialized and typically involves writing code for embedded systems or
operating systems where you have direct control over hardware resources. Below is a simplified C++ example
illustrating the concept of controlling a robot arm using memory-mapped I/O in a hypothetical embedded
system:
#include <cstdint>// for fixed-size integer types: int8_t, int32_t, int64_t, uint32_t, uint64_t
// Define memory-mapped addresses for robot arm control
volatile uint32_t* CONTROL_REG = reinterpret_cast<volatile uint32_t*>(0x20000000); // Declare a pointer
'CONTROL_REG' as a volatile pointer to a 32-bit unsigned integer and initialize it to the memory address
'0x20000000' after performing a reinterpret_cast for low-level memory access.
volatile uint32_t* ARM_POSITION_REG = reinterpret_cast<volatile uint32_t*>(0x20000004); //Define constants for
arm movements
constexpr uint8_t ARM_MOVE_LEFT = 0x01; // 0x01 represents the decimal value 1.
constexpr uint8_t ARM_MOVE_RIGHT = 0x02; //0x01 represents the decimal value 2.
constexpr uint8_t ARM_STOP = 0x00; //0x01 represents the decimal value 0.
14
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.
#include <iostream>#include <cstdint> //Platform-independent way to work with integers of
specific sizes.
// Placeholder memory-mapped addresses for robot arm control registers
volatile uint32_t* ROBOT_BASE_ADDRESS = reinterpret_cast<volatile uint32_t*>(0x30000000);
//Declare a pointer 'ROBOT_BASE_ADDRESS' as a volatile pointer to a 32-bit unsigned integer,
and initialize it to the memory address '0x30000000' after performing a reinterpret_cast for
low-level memory access.
volatile uint32_t* MOVE_LEFT_REGISTER = ROBOT_BASE_ADDRESS + 0x04; //Declare a pointer
'MOVE_LEFT_REGISTER' as a volatile pointer to a 32-bit unsigned integer and set it to point to
the memory location at an offset of 4 bytes from 'ROBOT_BASE_ADDRESS' for low-level
memory access.
volatile uint32_t* MOVE_RIGHT_REGISTER = ROBOT_BASE_ADDRESS + 0x08;
// Example base 32 integer address//Volatile can change the variable anytime
15
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.
16
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.
int main() {
std::cout << "Robot arm is in the default position" << std::endl;
// Simulate moving the robot arm left and right using MMIO
moveLeft(); // or you can use moveRight();
std::cout << "Robot arm is moving left" << std::endl;
for (volatile int i = 0; i < 1000000; ++i) {// Add a delay with Iterate a volatile integer 'i' from 0 to 999,999
in a loop.
asm volatile("nop"); } //Execute an assembly language instruction "nop" (no operation) within
the loop, providing a brief pause or delay. //"no-operation" (nop)//asm is a keyword used to indicate
the start of inline assembly code.
std::cout << "Robot arm is moving right" << std::endl;
17
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.
// Stop the robot arm (clear both "move left" and "move right" bits)
*MOVE_LEFT_REGISTER = 0;
*MOVE_RIGHT_REGISTER = 0; //Set the value pointed to by 'MOVE_RIGHT_REGISTER' to 0.
std::cout << "Robot arm is stopped" << std::endl;
return 0;}
18
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Designing and implementing custom memory allocators.
Designing/implementing a custom memory allocator in C++ involves managing memory allocation and
deallocation more efficiently or addressing specific application requirements.
public:
CustomAllocator() {}
void* allocate(size_t size) {// Allocate memory of a specified size
void* ptr = std::malloc(size); // Allocate memory of the specified 'size' using 'std::malloc' and
store the pointer to the allocated memory in 'void* ptr'.
19
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Designing and implementing custom memory allocators.
if (!ptr) {throw std::bad_alloc(); } // If the pointer 'ptr' is null, it triggers an exception of type
'std::bad_alloc()' to handle memory allocation failure.
return ptr;}
// Handle Allocation Failure: The exclamation mark (!) is a logical NOT operator.//throw std::bad_alloc();
is used to explicitly throw an exception of the std::bad_alloc type, indicating a failure in memory
allocation. This exception can then be caught and handled by an appropriate exception handler further up
the call stack, allowing the program to respond to the memory allocation failure gracefully.
➢ "Further up the call stack" means that when an exception is thrown, the C++ runtime looks for an
exception handler in the sequence of function calls that led to the exception. It searches from the
current function back to the caller functions to find the first suitable handler to deal with the
exception. This allows for structured error handling and recovery even if the error occurred deep
within nested function calls.
20
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Designing and implementing custom memory allocators.
// Deallocate memory
void deallocate(void* ptr) {std::free(ptr);} ~CustomAllocator() {}}; //Define a 'deallocate' function that
takes a pointer 'ptr' and deallocates the memory using 'std::free,' and a destructor for 'CustomAllocator'
int main() {
CustomAllocator allocator; // Allocate memory using the custom allocator
int* intArray = static_cast<int*>(allocator.allocate(sizeof(int) * 5)); // Allocate memory for a readable
integer array of size 5 using a custom allocator, and indicate that the pointer represents an 'int*' array by
explicit casting.
// Use the allocated memory
for (int i = 0; i < 5; ++i) { intArray[i] = i * 10; }
// Deallocate the memory
allocator.deallocate(intArray);
return 0;}
21
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.
❑ Memory pool management is a technique used in software development to enhance performance and
reduce memory fragmentation. It involves pre-allocating a fixed-sized block of memory, known as a
MEMORY POOL, and then efficiently managing the allocation and deallocation of memory chunks from
within this pool. This approach can lead to several benefits:
• Reduced memory overhead
• Faster memory allocation
• Improved memory locality.
➢ Memory pool management is particularly useful in scenarios where memory allocation and deallocation
occur frequently, such as in real-time systems, embedded systems, or image processing applications. By
pre-allocating a pool of memory chunks and reusing them, you can minimize the overhead of dynamic
memory allocation and deallocation, which can be costly in terms of time and resources.
22
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.
void* allocate(size_t size) {if (size <= CHUNK_SIZE) {for (auto& chunk : pool_) {if (!chunk.allocated) {
chunk.allocated = true;
//Define a member function 'allocate' that takes a 'size_t' 'size' and, if 'size' is less than or equal to
'CHUNK_SIZE,' it searches through the 'pool_' for an unallocated 'MemoryChunk,' sets its 'allocated' flag to
'true,' and returns the 'data' pointer of that 'MemoryChunk'.
return chunk.data;}}}
return nullptr; // Allocation failed}
23
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.
private: struct MemoryChunk {bool allocated = false;//Define a private nested struct 'MemoryChunk' that
contains a boolean member 'allocated' initialized to 'false’
char data[CHUNK_SIZE];};
std::vector<MemoryChunk> pool_;};
24
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.
// Image processing function using memory pool
void processImage(MemoryPool& pool) {
➢ processImage is the name of the function. It's a user-defined function.
➢ MemoryPool is a custom class or library that provides memory allocation and management services.
➢ pool is a parameter of the MemoryPool& type. It represents an instance of the MemoryPool class or object that is passed
to the processImage function as an argument.
➢ The & in the function parameter MemoryPool& pool indicates that pool is passed by reference.
// Allocate memory from the pool
void* imageData = pool.allocate(64); // The 64 represents the size, in bytes, of the memory block that is being allocated.
// Simulate image processing (copy data)
if (imageData) {
std::memcpy(imageData, "Image Data", 11); // Copies the content of the string "Image Data" (including the null
terminator) into the memory location pointed to by imageData
25
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.
➢ imageData is originally declared as a void* pointer, which means it doesn't specify the type of data it points to. By using
static_cast<char*>(imageData), you are telling the compiler to treat imageData as if it's pointing to a sequence of
characters (bytes).
➢ This cast allows you to work with the data pointed to by imageData as a sequence of characters, which is common when
dealing with binary data, raw memory, or byte-level manipulations.
27
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.
int main() {
MemoryPool pool;
// Perform image processing with memory pool management
processImage(pool);
// Calling a function named processImage and passing a variable or object pool as an argument to the function.
❑ This is a common practice in programming to INVOKE a Function or Method with specific data or resources
for further processing or computation.
return 0;}
28
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
Integrating custom allocators into data structures in C++ involves designing data structures that
allow users to provide their own memory allocation strategies. This customization can be essential
for:
• Optimizing memory usage
• Improving performance
• Accommodating specific application requirements
❑ By integrating custom allocators, data structures can be more flexible and adaptable. Users can
choose how memory is allocated, which can be particularly valuable in scenarios where standard
memory allocation techniques are not suitable, such as real-time systems, embedded
environments, or when dealing with specialized hardware.
29
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
Let’s review an example to illustrates how to integrate custom allocators into a simple vector-like
data structure, providing users with the flexibility to manage memory allocation according to their
needs. In summary we will have:
• We define a CustomAllocator class that provides custom memory allocation and deallocation
methods.
• The CustomVector class is similar to the standard vector but allows users to specify a custom
allocator when creating an instance.
• The CustomVector class uses the custom allocator to allocate and deallocate memory for its
elements.
• In the main function, we will create a CustomVector of integers and populate it with values,
demonstrating how to use a custom allocator with the data structure.
30
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
31
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
// Custom vector-like data structure with integrated custom allocator
template <typename T, typename Allocator = CustomAllocator<T>>
//Define a template class with a primary template that takes a type 'T' and an optional template
parameter 'Allocator,' defaulting to 'CustomAllocator<T>.
class CustomVector {
public: CustomVector() : data(nullptr), size_(0), capacity_(0) {}
//Define a public constructor for the 'CustomVector' class that initializes the 'data' pointer to 'nullptr,'
'size_' to 0, and 'capacity_' to 0
explicit CustomVector(size_t initialCapacity, const Allocator& alloc = Allocator())
//Define an explicit constructor for the 'CustomVector' class that takes 'initialCapacity' as a size
parameter and an optional 'alloc' parameter of type 'Allocator' with a default value of 'Allocator()’.” An
explicit constructor is used to prevent implicit type conversions during object construction.
32
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
data[size_++] = value;} // Assign the 'value' to the 'data' array at the current 'size_' index and then
increment 'size_'
33
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
➢ 1: This is the value that is chosen if the condition (capacity_ == 0) is true. In this case, if the capacity is
➢ : This colon separates the true and false branches of the conditional.
➢ capacity_ * 2: This is the value that is chosen if the condition (capacity_ == 0) is false. If the capacity is
34
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
➢ The ~CustomVector() function is a destructor that gets called when an instance of the
CustomVector class goes out of scope or is explicitly destroyed. In this case, it deallocates the
memory that was previously allocated for the vector's data using the custom allocator's deallocate
method.
This ensures that the memory is released when the vector is no longer needed, preventing memory
leaks.
36
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
private: T* data; //Declare a private member variable 'data' of type 'pointer to T', where 'T' can be any
data type.
size_t size_; //Declare a variable 'size_' of type 'size_t’ which is unsigned integer type
size_t capacity_; //Declare a variable 'capacity_' of type 'size_t'.
Allocator allocator; //Declare an instance of an 'Allocator' named 'allocator'
void reserve(size_t newCapacity) { //Define a function named 'reserve' that takes a size_t
parameter 'newCapacity'
T* newData = allocator.allocate(newCapacity);
//Allocate a new memory block of size 'newCapacity' using the 'allocator' and store the address in the
pointer 'newData'
for (size_t i = 0; i < size_; ++i) {newData[i] = data[i];}
37
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
❑ In the class's private section, vital components are defined for efficient data and memory management.
These include T* data for allocated data, size_t size_ to track element count, and size_t capacity_ for
capacity. The Allocator instance manages memory, and the void reserve(size_t newCapacity) function
efficiently allocates and copies data when needed, ensuring effective resource utilization.
38
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
39
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
We dynamically resize the previous allocated memories with the defined allocator and deallocator:
1. Allocates fresh memory with specified capacity.
2. Efficiently transfers existing data.
3. Deallocates old memory to prevent leaks.
4. Updates data pointer.
5. Adjusts capacity to new size, optimizing memory and performance.
40
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
int main() {
CustomVector<int> vec;
//Create an empty 'CustomVector' container of integers named 'vec’
for (int i = 1; i <= 10; ++i) {vec.push_back(i);}
//Add integers from 1 to 10 to the 'vec' container using 'push_back'
std::cout << "Vector size: " << vec.size() << std::endl; //vec.size() determines the size of the 'vec' container
for (size_t i = 0; i < vec.size(); ++i) {std::cout << vec[i] << " ";}
//Loop through the elements of 'vec' and print each element followed by a space.
std::cout << std::endl;
return 0;}
41
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).
Mark-and-Sweep:
Mark-and-Sweep is a simple garbage collection algorithm that can be implemented in C++. It
works in two phases:
• Marking
• Sweeping
42
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).
❑ Marking Phase: In this phase, the algorithm IDENTIFIES all the memory objects that are
still in use by the program. It starts from root objects (e.g., global variables or objects on
the call stack) and recursively traverses the object graph, marking each visited object as
"alive.“
❑ Sweeping Phase: After marking, the algorithm scans the entire heap memory, freeing or
"sweeping" away any unmarked memory blocks. These unmarked blocks are considered
garbage because they are no longer accessible from the program.
43
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).
44
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).
#include <iostream>
#include <vector>
// Define a simple object structure
struct MyObject {
int value;
bool marked;
MyObject* next;}; //Mark the 'next' object in the sequence recursively
//STEP 1: Function to mark objects as reachable
void mark(MyObject* obj);
{if (obj && !obj->marked) {obj->marked = true; //If 'obj' exists and is not marked, mark it as 'true'
mark(obj->next);}} //Mark the 'next' object in the sequence recursively
46
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).
47
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).
We define a MyObject structure that includes a marked flag to indicate whether an object is
reachable.
The mark function recursively marks objects as reachable starting from a root object.
The sweep function deallocates unmarked objects and removes them from the vector.
In the main function, we create objects, simulate references between them, mark them as
reachable, and then sweep and deallocate unmarked objects.
49
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.
Strengths:
• Automatic memory management reduces memory-related errors.
• Enhanced safety improves program reliability.
• Easier development and maintenance due to reduced manual memory management.
• Efficient dynamic memory handling for complex lifetimes.
Weaknesses:
• Runtime overhead and non-deterministic pauses can impact performance.
• Resource consumption may be high.
• Limited control over memory management compared to C++.
50
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.
Java
Automatic Garbage Collection: Java uses an automatic garbage collector that runs in the background and
manages memory for you. You don't need to explicitly allocate or deallocate memory.
Object Lifecycle: When you create objects in Java, they are allocated memory on the heap. The garbage
collector keeps track of which objects are still reachable from the program's root references (e.g., local
variables, object references).
Mark-and-Sweep: Java's garbage collector typically uses a generational garbage collection algorithm, which
includes a combination of techniques like mark-and-sweep and generational collection. Younger objects are
collected more frequently, while older ones are collected less often.
Tuning and Profiling: In Java, you can tune the garbage collector's behavior using command-line options or
configuration files. Profiling tools help you analyze and optimize garbage collection behavior for your specific
application.
51
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.
C#
Garbage Collection in .NET: C# also provides automatic garbage collection through the Common Language
Runtime (CLR) in the .NET framework. Memory management is similar to Java, and you don't need to
manually allocate or deallocate memory.
Object Lifecycle: In C#, objects are allocated memory on the managed heap. The garbage collector tracks
object references and determines which objects are still in use.
Generational Garbage Collection: Like Java, C# uses generational garbage collection. It divides objects into
different generations based on their age. Newly created objects are placed in the youngest generation, and
they are collected more frequently. Older objects are promoted to older generations and are collected less
frequently.
Memory Profiling: .NET provides memory profiling tools like Visual Studio Profiler and third-party tools to
analyze and optimize memory usage and garbage collection behavior.
52
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.
Practical Steps:
❑ In both Java and C#, you focus on writing your application code without worrying about manual
memory management.
❑ Use constructors to create objects, and the garbage collector takes care of reclaiming memory when
objects are no longer reachable.
❑ Be mindful of object references, especially when dealing with long-lived objects or event handlers, to
avoid unintentional memory leaks.
❑ Use profiling tools to identify memory-related issues, optimize memory usage, and fine-tune garbage
collection settings if necessary.
❑ In summary, practical implementation of garbage collection in Java and C# involves leveraging the
automatic garbage collection mechanisms provided by these languages and using profiling tools to
ensure efficient memory management and performance.
53
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Real-time and concurrent garbage collection.
1. Real-Time GC: Ensures predictable and low-latency responses in critical applications. Collects
garbage incrementally, minimizing pause times, and allowing for real-time system performance.
2. Concurrent GC: Runs concurrently with the application, reducing pause times. Collects garbage
without stopping the program, making it suitable for interactive and server applications.
❑ Both techniques prioritize minimizing interruptions, critical for applications with severe
performance requirements.
54
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Using profiling tools to analyze memory usage.
Profiling Tools: Utilize profiling tools to inspect memory usage, identify leaks, and discover performance
bottlenecks
• Heap Analysis: Analyze heap memory to pinpoint objects causing issues, enabling targeted
optimization.
• Resource Efficiency: Optimize memory usage for improved application performance and reduced
resource consumption.
• Critical for Scalability: Memory profiling is essential for ensuring applications scale efficiently as they
grow.
❑ Common profiling tools: Valgrind, gprof, Intel VTune Profiler, gperftools (Google Performance Tools), Perf,
Cachegrind, Heaptrack, Callgrind, gdb (GNU Debugger), AMD CodeXL
55
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Memory optimization techniques like object pooling.
Object Pooling: A memory optimization technique that reuses pre-allocated objects, reducing
memory fragmentation and allocation overhead. Ideal for scenarios with frequent object
creation and destruction.
C++ DOES NOT have a built-in standard library for object pooling. Object pooling is typically
implemented as a custom solution or using third-party libraries.
Common object pooling libraries: Boost Pool, ObjectPool, Boost Object Pool, and
MemoryPoolCPP.
56
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Memory optimization techniques like object pooling.
#include <iostream>
#include "ObjectPool.h" // Include the library header
int main() {// Create an object pool for integers
ObjectPool<int> intPool(10); // Pool size is 10
int* num1 = intPool.acquire(); // Acquire objects from the pool
int* num2 = intPool.acquire();
*num1 = 1001; // Use the acquired objects
*num2 = 1002;
intPool.release(num1); // Release objects back to the pool
intPool.release(num2);
return 0;}
57
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Reducing memory fragmentation in long-running applications.
58
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).
❑ Achieving memory safety in languages like C/C++ through techniques such as Resource
Acquisition Is Initialization (RAII) and smart pointers.
❑ RAII: A C++ programming technique that ensures resources (like memory) are automatically
managed by tying their acquisition and release to the lifetime of an object. When an object is
created, it acquires the resource, and when it goes out of scope or is explicitly destroyed, it
releases the resource, thereby preventing resource leaks.
59
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).
❑ Creating RAII (Resource Acquisition Is Initialization) involves designing a C++ class in a way that resource
management is tied to the object's lifecycle. Here are the steps to create an RAII class:
1. Identify the Resource: Determine the resource you want to manage. It can be memory, a file, a network
connection, or any resource that requires explicit acquisition and release.
2. Create the Class: Define a C++ class specifically for managing this resource. This class will acquire the resource in
its constructor and release it in its destructor.
3. Constructor (Resource Acquisition): In the class constructor, write code to acquire the resource. For example, if
you're managing a file, you might open the file in the constructor.
4. Destructor (Resource Release): In the class destructor, write code to release the resource. For example, if you
opened a file in the constructor, you should close the file in the destructor.
5. Use the Class: Instantiate objects of this class wherever you need to work with the resource. RAII ensures that
the resource is automatically acquired when the object is created and released when the object goes out of
scope (e.g., at the end of a function or block).
60
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).
#include <iostream>
#include <fstream>
#include <stdexcept> //To throw an exception if there's an issue with opening the file for resource management.
class FileResource {public:
FileResource(const std::string& filename) : file(filename)
{if (!file.is_open()) {throw std::runtime_error("Failed to open file");}}
~FileResource() {if (file.is_open()) {file.close();}} // This is the destructor of the FileResource class. It is automatically
called when an object of the class goes out of scope or is explicitly destroyed.
private:// Add methods to operate on the file here
std::ofstream file;};
int main() {try {
FileResource resource("example.txt"); // RAII: FileResource automatically manages the file
resource.file << "Hello, RAII!" << std::endl; // Use the resource as needed (e.g., write to the file)
} // Resource is automatically released when 'resource' goes out of scope
catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}
return 0;} 61
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).
➢ ~FileResource() // This is the destructor of the FileResource class with the tilde sign. It is automatically called
when an object of the class goes out of scope or is explicitly destroyed.
62
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory management in managed languages (e.g., Java, C#).
➢ Garbage collection is a core mechanism, where the runtime periodically identifies and reclaims
memory that is no longer in use, preventing common issues like memory leaks and dangling pointers.
➢ This approach simplifies memory management for developers BUT MAY INTRODUCE some runtime
overhead.
63
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Comparing Rust's ownership system with other languages.
Rust: A systems programming language that offers a unique approach to memory safety through its ownership
system.
❑ Unlike languages like C# and Java with garbage collection, Rust relies on compile-time checks to enforce
memory safety.
❑ This approach provides strong guarantees without runtime overhead, making Rust suitable for systems
programming and high-performance applications. Comparatively, languages like C and C++ rely more on
manual memory management, making them prone to memory-related bugs if not used carefully.
❑ Rust uses concepts like ownership, borrowing, and lifetimes to prevent common issues such as null pointer
dereferences and data races.
64
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Comparing Rust's ownership system with other languages.
Ownership: In Rust, ownership defines rules about which part of the code is responsible for managing a
resource's memory, ensuring its proper allocation and deallocation.(Memory Management Responsibilities)
Borrowing: Borrowing in Rust allows temporary access to a resource without transferring ownership,
ensuring that multiple parts of the code can use data safely.
Lifetime: Lifetimes in Rust specify the scope or duration for which references to data are valid, preventing the
use of references after the data is destroyed.
Buffer overflow: vulnerability where data overflows the allocated storage buffer's boundaries, potentially
overwriting adjacent memory, leading to unintended consequences: Crashes, Security Breaches, or Arbitrary
Code Execution.
65
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Comparing Rust's ownership system with other languages.
Runtime Overhead: Runtime overhead refers to the additional processing time and resources consumed by a
program due to runtime activities, such as garbage collection or dynamic memory allocation.
Data Race: A data race occurs in concurrent programming when two or more threads access shared data
simultaneously, potentially leading to unexpected and erroneous behavior.
Null Pointer Dereferencing: Null pointer dereferencing is the act of attempting to access or manipulate the
memory pointed to by a null (invalid) pointer, which can lead to crashes or undefined behavior.
Memory Bugs: Memory bugs are programming errors related to memory management, such as leaks
(unreleased memory), buffer overflows, or accessing uninitialized memory, which can result in program
instability or security vulnerabilities.
66
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Advanced Techniques in Virtual Memory:
Paging and segmentation in virtual memory systems.
Paging and segmentation are memory management techniques used in virtual memory systems.
Paging involves Dividing physical memory and virtual memory into Fixed-Size blocks (pages) and managing
them independently. It allows for efficient memory allocation but can lead to fragmentation.
Segmentation Divides memory into segments of Variable Sizes, each representing a logical unit. It offers
flexibility but may lead to fragmentation and complexity.
❑ In both cases we have fragmentation (losing actual memory) in the penalty of achieving efficient
memory management (Gaining efficient virtual memory access). So, these techniques enable efficient
memory allocation and protection in virtual memory systems, catering to diverse application needs and
system requirements.
67
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Advanced Techniques in Virtual Memory:.
Memory protection mechanisms and access control.
❑ Why virtual memory systems? It provides Memory Protection Mechanisms and ensures: data integrity
and system stability by controlling access to memory regions. These mechanisms enforce restrictions
on memory operations, preventing unauthorized modifications or access to protected memory areas,
enhancing security and stability in complex computing environments.
❑ How it works? As a C++ programmer, you don't need to call or manage virtual memory explicitly. The
operating system handles it behind the scenes. Your focus should be on proper memory management
practices within the C++ language, such as deallocating dynamically allocated memory to avoid
memory leaks and ensuring safe memory access to prevent issues like null pointer dereferences or
buffer overflows.
68
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Advanced Techniques in Virtual Memory:
Memory-mapped files and their applications.
Memory-mapped files allow files to be treated as regions of memory, facilitating efficient file I/O
operations by directly mapping file contents to virtual memory addresses. This technique enables
seamless integration of file data into a program's memory space, enhancing performance for tasks
like:
Process A
1. Large-scale data processing
69
Thank you
70