I am trying to simulate a memory leak problem with the following code and then investigate the system calls resulting in memory leak.
include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <ctime>
class SharedObject {
public:
std::string currentTime;
SharedObject() {
// Capture current time as string
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
currentTime = std::ctime(&now); // Convert time to string
}
void displayTime() {
std::cout << "Current Time: " << currentTime;
}
};
void threadFunction(const std::string& threadName, int totalIterations) {
for (int iteration = 1; iteration <= totalIterations; ++iteration) {
SharedObject* obj = new SharedObject(); // Create object
std::cout << threadName << " created an object at iteration " << iteration << std::endl;
obj->displayTime();
// Every 100 iterations, forget to delete the object (simulating memory leak)
if (iteration % 2 == 1) {
std::cout << threadName << " forgot to delete the object at iteration " << iteration << std::endl;
} else {
delete obj; // Delete object
std::cout << threadName << " deleted the object at iteration " << iteration << std::endl;
}
// Sleep for 512 milliseconds
std::this_thread::sleep_for(std::chrono::milliseconds(512));
}
std::cout << threadName << " completed all iterations.n";
}int main() {
const int totalIterations = 100000;
// Launch two threads
std::thread thread1(threadFunction, "Thread 1", totalIterations);
std::thread thread2(threadFunction, "Thread 2", totalIterations);
// Wait for threads to finish
thread1.join();
thread2.join();
std::cout << "Both threads completed execution.n";
return 0;
}
I have compiled and running the program in Linux soumajit-HP-Pavilion-Desktop-590-p0xxx 5.4.0-150-generic #167~18.04.1-Ubuntu SMP Wed May 24 00:51:42 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux system
Post that I am trying to trace malloc
and free
system call using strace
.
Following is the output
[pid 18031] <... stat resumed> {st_mode=S_IFREG|0644, st_size=312, ...}) = 0
[pid 18032] write(1, "Current Time: Tue Jan 14 23:08:3"..., 39) = 39
[pid 18031] futex(0x7fcf11c08c20, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 18032] write(1, "Thread 2 deleted the object at i"..., 46) = 46
[pid 18031] <... futex resumed> ) = 0
[pid 18032] nanosleep({tv_sec=0, tv_nsec=512000000}, <unfinished ...>
[pid 18031] write(1, "Thread 1 created an object at it"..., 45) = 45
[pid 18031] write(1, "Current Time: Tue Jan 14 23:08:3"..., 39) = 39
[pid 18031] write(1, "Thread 1 forgot to delete the ob"..., 55) = 55
[pid 18031] nanosleep({tv_sec=0, tv_nsec=512000000}, <unfinished ...>
[pid 18032] <... nanosleep resumed> 0x7fcf10c7ace0) = 0
[pid 18032] stat("/etc/localtime", <unfinished ...>
[pid 18031] <... nanosleep resumed> 0x7fcf1147bce0) = 0
[pid 18032] <... stat resumed> {st_mode=S_IFREG|0644, st_size=312, ...}) = 0
[pid 18031] futex(0x7fcf11c08c20, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 18032] futex(0x7fcf11c08c20, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 18031] <... futex resumed> ) = -1 EAGAIN (Resource temporarily unavailable)
[pid 18032] <... futex resumed> ) = 0
[pid 18031] stat("/etc/localtime", <unfinished ...>
[pid 18032] write(1, "Thread 2 created an object at it"..., 45 <unfinished ...>
[pid 18031] <... stat resumed> {st_mode=S_IFREG|0644, st_size=312, ...}) = 0
[pid 18032] <... write resumed> ) = 45
[pid 18032] write(1, "Current Time: Tue Jan 14 23:08:3"..., 39 <unfinished ...>
[pid 18031] futex(0x7fcf11c08c20, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 18032] <... write resumed> ) = 39
[pid 18031] <... futex resumed> ) = 0
[pid 18032] write(1, "Thread 2 forgot to delete the ob"..., 55 <unfinished ...>
[pid 18031] futex(0x7fcf11c088c0, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 18032] <... write resumed> ) = 55
[pid 18032] futex(0x7fcf11c088c0, FUTEX_WAKE_PRIVATE, 1) = 1
[pid 18031] <... futex resumed> ) = 0
[pid 18032] nanosleep({tv_sec=0, tv_nsec=512000000}, <unfinished ...>
[pid 18031] futex(0x7fcf11c088c0, FUTEX_WAKE_PRIVATE, 1) = 0
[pid 18031] write(1, "Thread 1 created an object at it"..., 45) = 45
[pid 18031] write(1, "Current Time: Tue Jan 14 23:08:3"..., 39) = 39
[pid 18031] write(1, "Thread 1 deleted the object at i"..., 46) = 46
[pid 18031] nanosleep({tv_sec=0, tv_nsec=512000000},
Why does the memory allocation and de-allocation calls not captured ?
[![ldd binary][1]][1]
[![ldd binary and ltrace version][1]][1]
2
Answers
strace
is short for "system call/signal trace". There are some system calls related to memory management (sbrk/brk/mmap
) but those are low-level and not useful to debug memory leaking issues.If you want to trace memory leaks you can use something like the AddressSanitizer available in g++/clang++:
(I limited the number of iterations to 10)
More info here.
You don’t see
malloc()
andfree()
because they are notsyscalls but wrappers around syscalls
implemented by libc. See for example how it is implemented in musl
libc (which is much easier to read than the infamous glibc):
If you want to analyze memory leaks in your program without
recompiling it you could use valgrind although
you’d get better results if you compiled the executable with
-g
.If you want to see calls to
malloc()
andfree()
you can useltrace, for example with this:
Build without optimizations:
Use ltrace: