unilink  0.4.3
A simple C++ library for unified async communication
memory_tracker.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2025 Jinwoo Sung
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <iomanip>
20 #include <iostream>
21 #include <sstream>
22 
24 
25 namespace unilink {
26 namespace memory {
27 
29  static MemoryTracker instance;
30  return instance;
31 }
32 
33 void MemoryTracker::track_allocation(void* ptr, size_t size, const char* file, int line, const char* function) {
34  if (!tracking_enabled_.load()) {
35  return;
36  }
37 
38  std::lock_guard<std::mutex> lock(allocations_mutex_);
39 
40  AllocationInfo info;
41  info.ptr = ptr;
42  info.size = size;
43  info.file = file ? file : "unknown";
44  info.line = line;
45  info.function = function ? function : "unknown";
46  info.timestamp = std::chrono::steady_clock::now();
47 
48  allocations_[ptr] = info;
49 
50  // Update statistics
51  stats_.total_allocations++;
52  stats_.current_allocations++;
53  stats_.total_bytes_allocated += size;
54  stats_.current_bytes_allocated += size;
55 
56  // Update peak values
57  if (stats_.current_allocations > stats_.peak_allocations) {
58  stats_.peak_allocations = stats_.current_allocations;
59  }
60  if (stats_.current_bytes_allocated > stats_.peak_bytes_allocated) {
62  }
63 }
64 
66  if (!tracking_enabled_.load()) {
67  return;
68  }
69 
70  std::lock_guard<std::mutex> lock(allocations_mutex_);
71 
72  auto it = allocations_.find(ptr);
73  if (it != allocations_.end()) {
74  size_t size = it->second.size;
75  allocations_.erase(it);
76 
77  // Update statistics
78  stats_.total_deallocations++;
79  stats_.current_allocations--;
80  stats_.total_bytes_deallocated += size;
81  stats_.current_bytes_allocated -= size;
82  }
83 }
84 
86 
87 std::vector<MemoryTracker::AllocationInfo> MemoryTracker::get_current_allocations() const {
88  std::lock_guard<std::mutex> lock(allocations_mutex_);
89 
90  std::vector<AllocationInfo> result;
91  result.reserve(allocations_.size());
92 
93  for (const auto& pair : allocations_) {
94  result.push_back(pair.second);
95  }
96 
97  return result;
98 }
99 
100 std::vector<MemoryTracker::AllocationInfo> MemoryTracker::get_leaked_allocations() const {
101  return get_current_allocations(); // Current allocations are potential leaks
102 }
103 
104 void MemoryTracker::enable_tracking(bool enable) { tracking_enabled_.store(enable); }
105 
106 void MemoryTracker::disable_tracking() { tracking_enabled_.store(false); }
107 
108 bool MemoryTracker::is_tracking_enabled() const { return tracking_enabled_.load(); }
109 
111  std::lock_guard<std::mutex> lock(allocations_mutex_);
112  allocations_.clear();
113 
114  // Reset statistics
115  stats_.total_allocations = 0;
116  stats_.total_deallocations = 0;
117  stats_.current_allocations = 0;
118  stats_.peak_allocations = 0;
119  stats_.total_bytes_allocated = 0;
120  stats_.total_bytes_deallocated = 0;
121  stats_.current_bytes_allocated = 0;
122  stats_.peak_bytes_allocated = 0;
123 }
124 
126  auto stats = get_stats();
127  auto current_allocations = get_current_allocations();
128 
129  std::cout << "\n=== Memory Tracker Report ===" << std::endl;
130  std::cout << "Total allocations: " << stats.total_allocations << std::endl;
131  std::cout << "Total deallocations: " << stats.total_deallocations << std::endl;
132  std::cout << "Current allocations: " << stats.current_allocations << std::endl;
133  std::cout << "Peak allocations: " << stats.peak_allocations << std::endl;
134  std::cout << "Total bytes allocated: " << stats.total_bytes_allocated << std::endl;
135  std::cout << "Total bytes deallocated: " << stats.total_bytes_deallocated << std::endl;
136  std::cout << "Current bytes allocated: " << stats.current_bytes_allocated << std::endl;
137  std::cout << "Peak bytes allocated: " << stats.peak_bytes_allocated << std::endl;
138  std::cout << "Current active allocations: " << current_allocations.size() << std::endl;
139 
140  if (!current_allocations.empty()) {
141  std::cout << "\n=== Current Allocations ===" << std::endl;
142  for (const auto& alloc : current_allocations) {
143  std::cout << "Ptr: " << alloc.ptr << ", Size: " << alloc.size << ", File: " << alloc.file << ":" << alloc.line
144  << ", Function: " << alloc.function << std::endl;
145  }
146  }
147 }
148 
150  auto leaked_allocations = get_leaked_allocations();
151 
152  if (leaked_allocations.empty()) {
153  std::cout << "\n=== No Memory Leaks Detected ===" << std::endl;
154  return;
155  }
156 
157  std::cout << "\n=== Memory Leak Report ===" << std::endl;
158  std::cout << "Found " << leaked_allocations.size() << " potential memory leaks:" << std::endl;
159 
160  size_t total_leaked_bytes = 0;
161  for (const auto& alloc : leaked_allocations) {
162  std::cout << "Leaked: " << alloc.size << " bytes at " << alloc.ptr << " allocated in " << alloc.file << ":"
163  << alloc.line << " (" << alloc.function << ")" << std::endl;
164  total_leaked_bytes += alloc.size;
165  }
166 
167  std::cout << "Total leaked bytes: " << total_leaked_bytes << std::endl;
168 }
169 
171  auto stats = get_stats();
172  auto current_allocations = get_current_allocations();
173 
174  std::ostringstream oss;
175  oss << "\n=== Memory Tracker Report ===\n";
176  oss << "Total allocations: " << stats.total_allocations << "\n";
177  oss << "Total deallocations: " << stats.total_deallocations << "\n";
178  oss << "Current allocations: " << stats.current_allocations << "\n";
179  oss << "Peak allocations: " << stats.peak_allocations << "\n";
180  oss << "Total bytes allocated: " << stats.total_bytes_allocated << "\n";
181  oss << "Total bytes deallocated: " << stats.total_bytes_deallocated << "\n";
182  oss << "Current bytes allocated: " << stats.current_bytes_allocated << "\n";
183  oss << "Peak bytes allocated: " << stats.peak_bytes_allocated << "\n";
184  oss << "Current active allocations: " << current_allocations.size();
185 
186  UNILINK_LOG_INFO("memory_tracker", "report", oss.str());
187 
188  if (!current_allocations.empty()) {
189  std::ostringstream alloc_oss;
190  alloc_oss << "\n=== Current Allocations ===\n";
191  for (const auto& alloc : current_allocations) {
192  alloc_oss << "Ptr: " << alloc.ptr << ", Size: " << alloc.size << ", File: " << alloc.file << ":" << alloc.line
193  << ", Function: " << alloc.function << "\n";
194  }
195  UNILINK_LOG_INFO("memory_tracker", "allocations", alloc_oss.str());
196  }
197 }
198 
200  auto leaked_allocations = get_leaked_allocations();
201 
202  if (leaked_allocations.empty()) {
203  UNILINK_LOG_INFO("memory_tracker", "leak_check", "No Memory Leaks Detected");
204  return;
205  }
206 
207  std::ostringstream oss;
208  oss << "\n=== Memory Leak Report ===\n";
209  oss << "Found " << leaked_allocations.size() << " potential memory leaks:\n";
210 
211  size_t total_leaked_bytes = 0;
212  for (const auto& alloc : leaked_allocations) {
213  oss << "Leaked: " << alloc.size << " bytes at " << alloc.ptr << " allocated in " << alloc.file << ":" << alloc.line
214  << " (" << alloc.function << ")\n";
215  total_leaked_bytes += alloc.size;
216  }
217 
218  oss << "Total leaked bytes: " << total_leaked_bytes;
219  UNILINK_LOG_ERROR("memory_tracker", "leak_check", oss.str());
220 }
221 
222 // ScopedMemoryTracker implementation
223 ScopedMemoryTracker::ScopedMemoryTracker(const char* file, int line, const char* function)
224  : file_(file), line_(line), function_(function) {}
225 
227  // Destructor can be used for cleanup if needed
228 }
229 
230 void ScopedMemoryTracker::track_allocation(void* ptr, size_t size) {
231  MemoryTracker::instance().track_allocation(ptr, size, file_, line_, function_);
232 }
233 
235 
236 } // namespace memory
237 } // namespace unilink
#define UNILINK_LOG_INFO(component, operation, message)
Definition: logger.hpp:265
#define UNILINK_LOG_ERROR(component, operation, message)
Definition: logger.hpp:279