1.添加内存申请释放记录代码。
This commit is contained in:
parent
d745f7d8c6
commit
fdd123b039
@ -26,7 +26,7 @@ set(ZLMediaKit_ROOT /opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit)
|
|||||||
set(ZLMediaKit_INCLUDE_DIR ${ZLMediaKit_ROOT}/include)
|
set(ZLMediaKit_INCLUDE_DIR ${ZLMediaKit_ROOT}/include)
|
||||||
set(ZLMediaKit_LIBRARY_DIRS ${ZLMediaKit_ROOT}/lib)
|
set(ZLMediaKit_LIBRARY_DIRS ${ZLMediaKit_ROOT}/lib)
|
||||||
|
|
||||||
if(${CROSS_BUILD})
|
if(CROSS_BUILD)
|
||||||
add_subdirectory(Main)
|
add_subdirectory(Main)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(Tools)
|
add_subdirectory(Tools)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "MemoryAllocationStackTracer.h"
|
#include "MemoryAllocationStackTracer.h"
|
||||||
|
#include "DateTime.h"
|
||||||
|
#include <boost/stacktrace/detail/addr_base.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -10,7 +12,8 @@ void *__wrap_malloc(size_t size) {
|
|||||||
void *address = __real_malloc(size);
|
void *address = __real_malloc(size);
|
||||||
auto self = MemoryAllocationStackTracer::instance();
|
auto self = MemoryAllocationStackTracer::instance();
|
||||||
if (address != nullptr && self->enabled()) {
|
if (address != nullptr && self->enabled()) {
|
||||||
self->push(reinterpret_cast<uint64_t>(address), MemoryAllocationStackTracer::Frame());
|
self->push(reinterpret_cast<uint64_t>(address),
|
||||||
|
MemoryAllocationStackTracer::Frame(1, static_cast<std::size_t>(-1)));
|
||||||
}
|
}
|
||||||
// printf("%p = malloc(%zu)\n", address, size);
|
// printf("%p = malloc(%zu)\n", address, size);
|
||||||
return address;
|
return address;
|
||||||
@ -26,9 +29,13 @@ void __wrap_free(void *__ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *operator new(std::size_t size) {
|
void *operator new(std::size_t size) {
|
||||||
// printf("void *operator new(std::size_t size),%zu\n", size);
|
void *address = __real_malloc(size);
|
||||||
|
auto self = MemoryAllocationStackTracer::instance();
|
||||||
return malloc(size);
|
if (address != nullptr && self->enabled()) {
|
||||||
|
self->push(reinterpret_cast<uint64_t>(address),
|
||||||
|
MemoryAllocationStackTracer::Frame(1, static_cast<std::size_t>(-1)));
|
||||||
|
}
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete(void *p) noexcept {
|
void operator delete(void *p) noexcept {
|
||||||
@ -37,8 +44,13 @@ void operator delete(void *p) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *operator new[](std::size_t count) {
|
void *operator new[](std::size_t count) {
|
||||||
// printf("%s", "void *operator new[](std::size_t count)\n");
|
void *address = __real_malloc(count);
|
||||||
return malloc(count);
|
auto self = MemoryAllocationStackTracer::instance();
|
||||||
|
if (address != nullptr && self->enabled()) {
|
||||||
|
self->push(reinterpret_cast<uint64_t>(address),
|
||||||
|
MemoryAllocationStackTracer::Frame(1, static_cast<std::size_t>(-1)));
|
||||||
|
}
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete[](void *ptr) noexcept {
|
void operator delete[](void *ptr) noexcept {
|
||||||
@ -46,24 +58,39 @@ void operator delete[](void *ptr) noexcept {
|
|||||||
return free(ptr);
|
return free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryAllocationStackTracer *MemoryAllocationStackTracer::m_instance = nullptr;
|
void operator delete(void *ptr, std::size_t sz, std::align_val_t al) noexcept {
|
||||||
|
return free(ptr);
|
||||||
void MemoryAllocationStackTracer::start() {
|
}
|
||||||
if (!m_enabled) {
|
void operator delete[](void *ptr, std::size_t sz, std::align_val_t al) noexcept {
|
||||||
m_enabled = true;
|
return free(ptr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryAllocationStackTracer *MemoryAllocationStackTracer::m_instance = nullptr;
|
||||||
|
|
||||||
void MemoryAllocationStackTracer::push(uint64_t address, Frame &&stacktrace) {
|
void MemoryAllocationStackTracer::push(uint64_t address, Frame &&stacktrace) {
|
||||||
|
if (stacktrace.empty()) return;
|
||||||
|
auto beginFrame = stacktrace.cbegin()->address();
|
||||||
|
if (m_counts.count(beginFrame) <= 0) {
|
||||||
|
m_counts.insert({beginFrame, 1});
|
||||||
|
} else {
|
||||||
|
m_counts[beginFrame]++;
|
||||||
|
}
|
||||||
|
|
||||||
Infomation info;
|
Infomation info;
|
||||||
info.time = std::chrono::system_clock::now();
|
info.time = std::chrono::system_clock::now();
|
||||||
info.frame = std::move(stacktrace);
|
info.frame = std::move(stacktrace);
|
||||||
m_stacktraces.insert({address, info});
|
m_stacktraces.insert({address, info});
|
||||||
// m_stacktraces.insert({address, stacktrace});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryAllocationStackTracer::pop(uint64_t address) {
|
void MemoryAllocationStackTracer::pop(uint64_t address) {
|
||||||
if (m_stacktraces.count(address) > 0) {
|
if (m_stacktraces.count(address) > 0) {
|
||||||
|
auto &info = m_stacktraces.at(address);
|
||||||
|
auto beginFrame = info.frame.cbegin()->address();
|
||||||
|
if (m_counts.count(beginFrame) > 0) {
|
||||||
|
if (m_counts.at(beginFrame) > 0) {
|
||||||
|
m_counts[beginFrame]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
m_stacktraces.erase(address);
|
m_stacktraces.erase(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,22 +104,65 @@ MemoryAllocationStackTracer *MemoryAllocationStackTracer::instance() {
|
|||||||
}
|
}
|
||||||
return m_instance;
|
return m_instance;
|
||||||
}
|
}
|
||||||
void MemoryAllocationStackTracer::dump() {
|
|
||||||
|
std::string MemoryAllocationStackTracer::dump() {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
std::cout << "size: " << m_stacktraces.size() << std::endl;
|
std::ostringstream oss;
|
||||||
|
oss << "size: " << m_stacktraces.size() << std::endl;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
std::ofstream ofs("test.txt");
|
|
||||||
for (auto &info : m_stacktraces) {
|
for (auto &info : m_stacktraces) {
|
||||||
std::ostringstream oss;
|
|
||||||
auto duration = duration_cast<seconds>(now - info.second.time);
|
auto duration = duration_cast<seconds>(now - info.second.time);
|
||||||
oss << "-----index[" << index << "] duration: " << duration.count() << "s:-----" << std::endl;
|
oss << "-----index[" << index << "] duration: " << duration.count() << "s:-----" << std::endl;
|
||||||
oss << info.second.frame << std::endl;
|
oss << info.second.frame << std::endl;
|
||||||
auto content = oss.str();
|
|
||||||
ofs << content;
|
|
||||||
std::cout << content;
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
// aarch64-linux-gnu-addr2line -e build/Tools/LeakTracer/LeakTracer 0x55caea8e4f62
|
||||||
|
|
||||||
|
for (auto &count : m_counts) {
|
||||||
|
auto addr_base = boost::stacktrace::detail::get_own_proc_addr_base(count.first);
|
||||||
|
oss << "address: " << std::hex << (count.first - addr_base) << ", count: " << count.second << std::endl;
|
||||||
|
}
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryAllocationStackTracer::run() {
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
while (!m_exit) {
|
||||||
|
auto start = system_clock::now();
|
||||||
|
|
||||||
|
while (!m_exit) {
|
||||||
|
std::this_thread::sleep_for(50ms);
|
||||||
|
auto now = system_clock::now();
|
||||||
|
auto elapsed = duration_cast<milliseconds>(now - start);
|
||||||
|
if (elapsed <= m_intervals) continue;
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << m_path << "/" << m_applicationName << "_" << DateTime(start).toString("%Y%m%d%H%M%S") << "-"
|
||||||
|
<< DateTime::currentDateTime().toString("%Y%m%d%H%M%S") << ".dump";
|
||||||
|
|
||||||
|
std::ofstream ofs(oss.str());
|
||||||
|
ofs << dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryAllocationStackTracer::stop() {
|
||||||
|
if (!m_exit) {
|
||||||
|
m_exit = true;
|
||||||
|
if (m_thread.joinable()) m_thread.join();
|
||||||
|
}
|
||||||
|
if (m_enabled) {
|
||||||
|
m_enabled = false;
|
||||||
|
}
|
||||||
|
m_stacktraces.clear();
|
||||||
|
m_counts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryAllocationStackTracer::~MemoryAllocationStackTracer() {
|
||||||
|
stop();
|
||||||
}
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <boost/stacktrace/stacktrace.hpp>
|
#include <boost/stacktrace/stacktrace.hpp>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -62,26 +63,62 @@ public:
|
|||||||
class MemoryAllocationStackTracer {
|
class MemoryAllocationStackTracer {
|
||||||
public:
|
public:
|
||||||
using Frame = boost::stacktrace::basic_stacktrace<DebugAllocator<boost::stacktrace::frame>>;
|
using Frame = boost::stacktrace::basic_stacktrace<DebugAllocator<boost::stacktrace::frame>>;
|
||||||
|
using String = std::basic_string<char, std::char_traits<char>, DebugAllocator<char>>;
|
||||||
|
using OutStringStream = std::basic_ostringstream<char, std::char_traits<char>, DebugAllocator<char>>;
|
||||||
class Infomation {
|
class Infomation {
|
||||||
public:
|
public:
|
||||||
std::chrono::system_clock::time_point time;
|
std::chrono::system_clock::time_point time;
|
||||||
Frame frame;
|
Frame frame;
|
||||||
};
|
};
|
||||||
|
~MemoryAllocationStackTracer();
|
||||||
static MemoryAllocationStackTracer *instance();
|
static MemoryAllocationStackTracer *instance();
|
||||||
inline bool enabled() const {
|
inline bool enabled() const {
|
||||||
return m_enabled;
|
return m_enabled;
|
||||||
}
|
}
|
||||||
void start();
|
|
||||||
void dump();
|
template <class Rep, class Period>
|
||||||
|
void start(const std::string &path, const std::string &applicationName,
|
||||||
|
const std::chrono::duration<Rep, Period> &intervals) {
|
||||||
|
if (m_exit) {
|
||||||
|
m_exit = false;
|
||||||
|
m_thread = std::thread(&MemoryAllocationStackTracer::run, this);
|
||||||
|
}
|
||||||
|
m_intervals = std::chrono::duration_cast<std::chrono::milliseconds>(intervals);
|
||||||
|
|
||||||
|
if (!m_enabled) {
|
||||||
|
m_enabled = true;
|
||||||
|
}
|
||||||
|
m_path = path;
|
||||||
|
m_applicationName = applicationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
std::string dump();
|
||||||
void push(uint64_t address, Frame &&stacktrace);
|
void push(uint64_t address, Frame &&stacktrace);
|
||||||
void pop(uint64_t address);
|
void pop(uint64_t address);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<uint64_t, Infomation, std::hash<uint64_t>, std::equal_to<uint64_t>,
|
std::unordered_map<uint64_t, Infomation, std::hash<uint64_t>, std::equal_to<uint64_t>,
|
||||||
DebugAllocator<std::pair<const uint64_t, Infomation>>>
|
DebugAllocator<std::pair<const uint64_t, Infomation>>>
|
||||||
m_stacktraces;
|
m_stacktraces;
|
||||||
|
|
||||||
|
std::unordered_map<boost::stacktrace::frame::native_frame_ptr_t, uint32_t,
|
||||||
|
std::hash<boost::stacktrace::frame::native_frame_ptr_t>,
|
||||||
|
std::equal_to<boost::stacktrace::frame::native_frame_ptr_t>,
|
||||||
|
DebugAllocator<std::pair<const boost::stacktrace::frame::native_frame_ptr_t, uint32_t>>>
|
||||||
|
m_counts;
|
||||||
|
|
||||||
static MemoryAllocationStackTracer *m_instance;
|
static MemoryAllocationStackTracer *m_instance;
|
||||||
|
std::string m_path;
|
||||||
|
std::string m_applicationName;
|
||||||
|
bool m_exit = true;
|
||||||
|
std::thread m_thread;
|
||||||
|
std::chrono::milliseconds m_intervals;
|
||||||
|
|
||||||
bool m_enabled = false;
|
bool m_enabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user