diff --git a/.gitignore b/.gitignore index d7dce0b..088380b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,5 @@ target_wrapper.* # QtCreator CMake CMakeLists.txt.user* +.idea build diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 9d1bee2..d4a4ffe 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -7,6 +7,7 @@ "${workspaceFolder}/3rdparty/ds_pedestrian_mot_hisi/include", "/opt/Libraries/boost_1_84_0/include", "/opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit/include", + "/opt/aarch64-v01c01-linux-gnu-gcc/lib/LeakTracer/include", "build/_deps/kylin-src/Universal" ], "defines": [], diff --git a/Tools/CMakeLists.txt b/Tools/CMakeLists.txt index 7b881a3..f636d6d 100644 --- a/Tools/CMakeLists.txt +++ b/Tools/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(LeakTracer) add_subdirectory(VideoRecoder) \ No newline at end of file diff --git a/Tools/LeakTracer/CMakeLists.txt b/Tools/LeakTracer/CMakeLists.txt new file mode 100644 index 0000000..4378822 --- /dev/null +++ b/Tools/LeakTracer/CMakeLists.txt @@ -0,0 +1,18 @@ +add_executable(LeakTracer main.cpp + # LeakTracer.h LeakTracer.cpp + MemoryAllocationStackTracer.h MemoryAllocationStackTracer.cpp +) + +target_include_directories(LeakTracer + PRIVATE ${Libraries_ROOT}/LeakTracer/include +) + +target_link_directories(LeakTracer + PRIVATE ${Libraries_ROOT}/LeakTracer +) + +target_link_libraries(LeakTracer + PUBLIC Universal + -Wl,--wrap=malloc + -Wl,--wrap=free +) \ No newline at end of file diff --git a/Tools/LeakTracer/LeakTracer.cpp b/Tools/LeakTracer/LeakTracer.cpp new file mode 100644 index 0000000..1928467 --- /dev/null +++ b/Tools/LeakTracer/LeakTracer.cpp @@ -0,0 +1,39 @@ +#include "LeakTracer.h" +#include "DateTime.h" +#include +#include + +LeakTracer::LeakTracer(const std::string &path, const std::string &applicationName) + : m_path(path), m_applicationName(applicationName) { +} + +LeakTracer::~LeakTracer() { + stop(); +} + +void LeakTracer::run() { + using namespace std::chrono; + using namespace std::chrono_literals; + while (!m_exit) { + auto start = system_clock::now(); + leaktracer_startMonitoringAllThreads(); + while (!m_exit) { + std::this_thread::sleep_for(50ms); + auto now = system_clock::now(); + auto elapsed = duration_cast(now - start); + if (elapsed >= m_intervals) break; + } + 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"; + leaktracer_writeLeaksToFile(oss.str().c_str()); + leaktracer_stopAllMonitoring(); + } +} + +void LeakTracer::stop() { + if (!m_exit) { + m_exit = true; + if (m_thread.joinable()) m_thread.join(); + } +} \ No newline at end of file diff --git a/Tools/LeakTracer/LeakTracer.h b/Tools/LeakTracer/LeakTracer.h new file mode 100644 index 0000000..43bdc8c --- /dev/null +++ b/Tools/LeakTracer/LeakTracer.h @@ -0,0 +1,34 @@ +#ifndef __AMASS_LEAKTRACER_H__ +#define __AMASS_LEAKTRACER_H__ + +#include +#include +#include + +class LeakTracer { +public: + LeakTracer(const std::string &path, const std::string &applicationName); + ~LeakTracer(); + + template + void start(const std::chrono::duration &intervals) { + if (m_exit) { + m_exit = false; + m_thread = std::thread(&LeakTracer::run, this); + } + m_intervals = std::chrono::duration_cast(intervals); + } + + void stop(); + +protected: + void run(); + +private: + bool m_exit = true; + std::string m_path; + std::string m_applicationName; + std::chrono::milliseconds m_intervals; + std::thread m_thread; +}; +#endif // __AMASS_LEAKTRACER_H__ \ No newline at end of file diff --git a/Tools/LeakTracer/MemoryAllocationStackTracer.cpp b/Tools/LeakTracer/MemoryAllocationStackTracer.cpp new file mode 100644 index 0000000..69a4dcf --- /dev/null +++ b/Tools/LeakTracer/MemoryAllocationStackTracer.cpp @@ -0,0 +1,63 @@ +#include "MemoryAllocationStackTracer.h" +#include +#include + +extern "C" { + +void *__wrap_malloc(size_t size) { + void *address = __real_malloc(size); + // if (address != nullptr) { + // MemoryAllocationStackTracer::instance()->push(reinterpret_cast(address), + // boost::stacktrace::stacktrace()); + // } + // std::cout << "malloc " << size << " bytes." << std::endl; + return address; +} + +void __wrap_free(void *__ptr) { + // if (__ptr != nullptr) { + // MemoryAllocationStackTracer::instance()->pop(reinterpret_cast(__ptr)); + // } + return __real_free(__ptr); +} +} + +void *operator new(std::size_t size) { + printf("new %d %d\n ", size, sizeof(boost::stacktrace::stacktrace)); + void *address = __real_malloc(size); + + // if (size != sizeof(boost::stacktrace::stacktrace) || size != 2048) { + // MemoryAllocationStackTracer::instance()->push(reinterpret_cast(address), + // boost::stacktrace::stacktrace()); + // } + + return address; +} + +void operator delete(void *p) { + free(p); +} + +MemoryAllocationStackTracer *MemoryAllocationStackTracer::m_instance = nullptr; + +void MemoryAllocationStackTracer::initialize() { + if (m_instance == nullptr) { + auto buffer = __real_malloc(sizeof(MemoryAllocationStackTracer)); + if (buffer != nullptr) { + m_instance = new (buffer) MemoryAllocationStackTracer(); + } + } +} + +void MemoryAllocationStackTracer::push(uint64_t address, const boost::stacktrace::stacktrace &stacktrace) { + m_stacktraces.insert({address, stacktrace}); +} + +void MemoryAllocationStackTracer::pop(uint64_t address) { + m_stacktraces.erase(address); +} + +MemoryAllocationStackTracer *MemoryAllocationStackTracer::instance() { + + return m_instance; +} diff --git a/Tools/LeakTracer/MemoryAllocationStackTracer.h b/Tools/LeakTracer/MemoryAllocationStackTracer.h new file mode 100644 index 0000000..0372324 --- /dev/null +++ b/Tools/LeakTracer/MemoryAllocationStackTracer.h @@ -0,0 +1,76 @@ +#ifndef __MEMORYALLOCATIONSTACKTRACER_H__ +#define __MEMORYALLOCATIONSTACKTRACER_H__ + +#include +#include + +extern "C" { +extern void *__real_malloc(size_t size); +extern void __real_free(void *__ptr); +} + +template +class DebugAllocator { +public: + using value_type = T; + using pointer = T *; + + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + template + struct rebind { + typedef DebugAllocator other; + }; + DebugAllocator() { + } + + template + DebugAllocator(const DebugAllocator &other) noexcept { + } + + T *allocate(std::size_t n) { + return reinterpret_cast(__real_malloc(n)); + } + void deallocate(T *p, std::size_t n) { + __real_free(p); + } + + template + void construct(U *p, Args &&...args) { + ::new ((void *)p) U(std::forward(args)...); + } + + template + void destroy(U *p) { + p->~U(); + } + + pointer address(reference x) { + return (pointer)&x; + } + + const_pointer address(const_reference x) { + return (const_pointer)&x; + } +}; + +class MemoryAllocationStackTracer { +public: + static void initialize(); + static MemoryAllocationStackTracer *instance(); + void push(uint64_t address, const boost::stacktrace::stacktrace &stacktrace); + void pop(uint64_t address); + +private: + std::unordered_map, std::equal_to, + DebugAllocator> + m_stacktraces; + + static MemoryAllocationStackTracer *m_instance; +}; + +#endif // __MEMORYALLOCATIONSTACKTRACER_H__ \ No newline at end of file diff --git a/Tools/LeakTracer/main.cpp b/Tools/LeakTracer/main.cpp new file mode 100644 index 0000000..fb93472 --- /dev/null +++ b/Tools/LeakTracer/main.cpp @@ -0,0 +1,37 @@ +#include "LeakTracer.h" +#include "MemoryAllocationStackTracer.h" +#include +#include +#include +#include +#include + +void test() { + std::cout << boost::stacktrace::stacktrace(); + malloc(20); +} + +int make_memory_leak(void) { + printf("%s:%d, 00!\n", __FILE__, __LINE__); + + int *ptr = (int *)malloc(sizeof(int)); // 分配内存块 + *ptr = 0; // 构造内存泄露 + printf("%s:%d, ptr= %p, *ptr= %d!\n", __FILE__, __LINE__, ptr, *ptr); + + char *p_new = new char[8 * 1024 * 1024]; + (void)memset(p_new, 0, 8 * 1024 * 1024); + *p_new = 0; + printf("%s:%d, p_new= %p, *p_new= %d!\n", __FILE__, __LINE__, p_new, *p_new); + + return 0; +} + +class Test { + int a; +}; + +int main(int argc, char const *argv[]) { + MemoryAllocationStackTracer::initialize(); + auto a = new Test(); + return 0; +} diff --git a/resources/build.sh b/resources/build.sh index 675029e..37b2c8b 100755 --- a/resources/build.sh +++ b/resources/build.sh @@ -62,6 +62,7 @@ function init() { echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/gdb-10.2/bin/gdbserver /system/bin" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "mkdir -p /data/sdcard/PassengerStatistics/lib" echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit/lib/libmk_api.so /data/sdcard/PassengerStatistics/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} + echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/LeakTracer/libleaktracer.so /data/sdcard/PassengerStatistics/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} # echo "put ${BOOST_LIBDIR}/libboost_date_time* /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} echo "put ${BOOST_LIBDIR}/libboost_regex.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} echo "put ${BOOST_LIBDIR}/libboost_log_setup.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} @@ -87,7 +88,7 @@ function deploy() { echo "deploy to target $TARGET_IP, path: ${TARGET_PATH} ..." echo "put ${build_path}/Main/PassengerStatistics ${TARGET_PATH}" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} echo "put ${build_path}/Tools/VideoRecoder/VideoRecoder ${TARGET_PATH}" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} - + echo "put ${build_path}/Tools/LeakTracer/LeakTracer ${TARGET_PATH}" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "sync" }