You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重载new/delete运算符时内存跟踪不准的问题及方案咨询

Hey there! Let's dig into your memory tracking problem and figure out how to get that precise tracking you want.

Why You're Seeing 8 Bytes Freed Instead of 4

The mismatch between the 4 bytes you requested for an int and the 8 bytes your delete handler reports is almost certainly due to allocator metadata or memory alignment requirements. Most heap allocators add small chunks of extra data to each allocation—things like block size, flags, or pointers to adjacent blocks—to manage the heap efficiently. Additionally, many systems enforce memory alignment (e.g., 8-byte alignment for 64-bit systems), so even small allocations get rounded up to the nearest alignment boundary.

When you call free() in your delete operator, you're seeing the actual total size the allocator reserved, not the size you requested. To fix this, we need to track the user-requested size instead.

How to Implement Precise Memory Tracking

Here's a revised approach that tracks exactly the memory you requested, plus adds support for tracking dynamic objects and their sizes:

First, update your global new/delete overloads to record the requested size when allocating, then look up that size when freeing:

#include <iostream>
#include <unordered_map>
#include <typeinfo>
#include <utility>

// Static tracking state (thread-safe note: add a mutex if using multi-threaded code!)
static std::unordered_map<void*, std::pair<size_t, const char*>> allocated_blocks;
static size_t total_requested_allocated = 0;
static size_t total_requested_freed = 0;

// Overload global new to track requested size and optional type info
void* operator new(size_t size, const char* type_name = "unknown") {
    void* ptr = malloc(size);
    if (ptr) {
        allocated_blocks[ptr] = {size, type_name};
        total_requested_allocated += size;
        std::cout << "[ALLOC] " << size << " bytes (" << type_name << ") at " << ptr << "\n";
    }
    return ptr;
}

// Overload global delete to use the tracked size
void operator delete(void* ptr) noexcept {
    if (!ptr) return;
    auto it = allocated_blocks.find(ptr);
    if (it != allocated_blocks.end()) {
        total_requested_freed += it->second.first;
        std::cout << "[FREE] " << it->second.first << " bytes (" << it->second.second << ") at " << ptr << "\n";
        allocated_blocks.erase(it);
    }
    free(ptr);
}

// Don't forget array allocations!
void* operator new[](size_t size, const char* type_name = "array-unknown") {
    return operator new(size, type_name);
}

void operator delete[](void* ptr) noexcept {
    operator delete(ptr);
}

// Helper template to track object types automatically
template<typename T, typename... Args>
T* tracked_new(Args&&... args) {
    return new(typeid(T).name()) T(std::forward<Args>(args)...);
}

Key Improvements Here:

  • We store the user-requested size in a map (linked to the allocation pointer) instead of relying on the allocator's reported size during deletion.
  • Added support for tracking object types using typeid, so you can see exactly what kind of object was allocated.
  • Included overloads for array new[]/delete[]—easy to forget, but critical for complete tracking.
  • Added a tracked_new template function to automatically pass type info without manual work.
Tracking Dynamic Objects

To track individual objects (not just raw memory), you can extend this setup in a couple ways:

1. Per-Class Tracking

If you want detailed stats for specific classes, add static counters and class-specific new/delete overloads:

class MyCustomObj {
private:
    int data[10];
    static size_t live_object_count;

public:
    MyCustomObj() { live_object_count++; }
    ~MyCustomObj() { live_object_count--; }

    // Class-specific new to track type automatically
    void* operator new(size_t size) {
        return ::operator new(size, typeid(MyCustomObj).name());
    }

    static size_t get_live_count() { return live_object_count; }
};

size_t MyCustomObj::live_object_count = 0;

2. Global Object Type Stats

You can modify the tracking map to aggregate stats by type:

#include <unordered_map>
static std::unordered_map<const char*, size_t> type_allocation_counts;

// Update the new operator to increment type counts
void* operator new(size_t size, const char* type_name = "unknown") {
    void* ptr = malloc(size);
    if (ptr) {
        allocated_blocks[ptr] = {size, type_name};
        total_requested_allocated += size;
        type_allocation_counts[type_name]++;
        std::cout << "[ALLOC] " << size << " bytes (" << type_name << ") at " << ptr << "\n";
    }
    return ptr;
}

// And update delete to decrement
void operator delete(void* ptr) noexcept {
    if (!ptr) return;
    auto it = allocated_blocks.find(ptr);
    if (it != allocated_blocks.end()) {
        total_requested_freed += it->second.first;
        type_allocation_counts[it->second.second]--;
        std::cout << "[FREE] " << it->second.first << " bytes (" << it->second.second << ") at " << ptr << "\n";
        allocated_blocks.erase(it);
    }
    free(ptr);
}

Example Usage

int main() {
    // Track a raw int
    int* int_ptr = tracked_new<int>();
    std::cout << "Total allocated: " << total_requested_allocated << " bytes\n";

    // Track a custom object
    MyCustomObj* obj_ptr = tracked_new<MyCustomObj>();
    std::cout << "Live MyCustomObj instances: " << MyCustomObj::get_live_count() << "\n";

    // Cleanup
    delete int_ptr;
    delete obj_ptr;
    std::cout << "Total freed: " << total_requested_freed << " bytes\n";
    std::cout << "Live MyCustomObj instances: " << MyCustomObj::get_live_count() << "\n";

    return 0;
}
Final Notes
  • Thread Safety: If your code is multi-threaded, wrap access to the static tracking maps with a std::mutex to avoid race conditions.
  • Allocation Edge Cases: Be aware of things like placement new (you'll need to handle those separately if they're used) and compiler optimizations that might elide allocations.
  • Debug Mode vs Release: Some allocators add even more metadata in debug builds—this approach will still track your requested size regardless.

内容的提问来源于stack exchange,提问作者Derek Johnson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:32:33