无法删除堆内存上的指针

时间:2019-12-05 07:26:35

标签: c++ pointers heap-memory dynamic-memory-allocation delete-operator

我正在用C ++制作自己的动态分配器。但是我遇到了无法释放记忆的问题。 这是Test.cpp的代码:

#include "Memory/MemoryManager.h"

int main(){
    initMemory(1);
    int* p = allocate<int>();
    int* q = allocate<int>();
    int* r = allocate<int>();
    cout<<p<<endl;
    cout<<q<<endl;
    cout<<r<<endl;
    freeAddress<int>(q);
    return 0;
}

MemoryManager.h:

#ifndef MEMORY_MANAGER_INCLUDED
#define MEMORY_MANAGER_INCLUDED

#include <iostream>
#include <map>
#include <memory>

using namespace std;

char* memory;
char* current;

map<void*, size_t> freePointers;

void initMemory(size_t size){
    memory = (char*)malloc(size);
    current = memory;
}

template<typename T> T* allocate(){
    T* address = NULL;
    for (auto p : freePointers){
        if (p.second == sizeof(T)){
            address = static_cast<T*>(p.first);
        }
    }

    if (address == NULL){
        address = new(current) T();
        current += sizeof(T);
    }

    return address;
}

template<typename T> T* allocate(size_t size){
    T* address = NULL;
    for (auto p : freePointers){
        if (p.second == sizeof(T) * size){
            return static_cast<T*>(p.first);
        }
    }

    if (address == NULL){
        address = new(current) T[size];
        current += sizeof(T) * size;
    }
    return address;
}

template<typename T> void freeAddress(T* address){
    freePointers.insert({(void*)address, sizeof(*address)});
    delete address;
}

template<typename T> void freeAddress(T* address, size_t size){
    freePointers.insert({(void*)address, sizeof(*address) * size});
    delete [] address;
}
#endif

输出:

0x55ee37729e70
0x55ee37729e74
0x55ee37729e78
0x55ee37729e70
0x55ee37729e78
free(): invalid pointer

我知道我无法删除堆栈存储器上的指针,但是我根本没有使用它。另外请指出我做错了什么还是性能有所提高。请帮忙。

2 个答案:

答案 0 :(得分:3)

您使用line.set_xdata((x1, Bx)) line.set_ydata((y1, By)) 分配了一大块内存,然后在某个指针上调用malloc进入已分配的内存。

在您的代码中,deleteq。该指针从未由分配返回,因此无法释放。这就是错误的原因。

此外,将(memory + sizeof(int))malloc不匹配是未定义的行为。最后,您应该在原始delete指针上调用free()作为清除,并且永远不要在单个值上调用memory

如果要在delete中调用析构函数,请使用freeAddress

答案 1 :(得分:0)

您一次在initMemory()中分配了一个1字节的内存块。您正在使用malloc()进行该分配,因此在完成使用free()时必须使用freeAddress()释放内存块,但是您没有这样做。

您的deletenew的内存,从未分配过allocate()。在new内部,您使用的是 placement-new 而不是free(),它们不是同一回事。使用 placement-new 时,您必须手动调用对象的析构函数,而不是deletenew[]

您当然不希望释放以后将要重用的内存。这样就无法达到缓存“已释放”内存的全部目的。

并且delete[]使用的内存超出了您的请求,因此它可以存储new[]的信息,以了解要释放多少元素以及如何释放它们。您将不知道这是多少,因为它是实现定义的。因此在这种情况下使用#include "Memory/MemoryManager.h" int main(){ initMemory(sizeof(int) * 3); int* p = allocate<int>(); int* q = allocate<int>(); int* r = allocate<int>(); cout << p << endl; cout << q << endl; cout << r << endl; freeAddress<int>(q); doneMemory(); return 0; } 是不安全的。

尝试更多类似的方法

#ifndef MEMORY_MANAGER_INCLUDED
#define MEMORY_MANAGER_INCLUDED

#include <iostream>
#include <map>
#include <memory>

char* memory;
char* current;
size_t available;
std::map<void*, size_t> freePointers;

void initMemory(size_t size){
    memory = (char*) malloc(size);
    current = memory;
    available = (memory) ? size : 0;
}

void doneMemory(){
    freePointers.clear();
    free(memory);
    memory = current = nullptr;
    available = 0;
}

template<typename T>
T* allocate(){
    T *address = nullptr;

    for (auto iter = freePointers.begin(); iter != freePointers.end(); ++iter){
        if (iter->second == sizeof(T)){
            address = static_cast<T*>(iter->first);
            freePointers.erase(iter);
            break;
        }
    }

    if (!address){
        if (available < sizeof(T)){
            return nullptr;
        }
        address = static_cast<T*>(current);
        current += sizeof(T);
        available -= sizeof(T);
    }

    return new(address) T();
}

template<typename T>
T* allocate(size_t count){
    T *address = nullptr;
    size_t size = count * sizeof(T);

    for (auto iter = freePointers.begin(); iter != freePointers.end(); ++iter){
        if (iter->second == size){
            address = static_cast<T*>(iter->first);
            freePointers.erase(iter);
            break;
        }
    }

    if (!address){
        if (available < size){
            return nullptr;
        }
        address = static_cast<T*>(current);
        current += size;
        available -= size;
    }

    for(size_t i = 0; i < count; ++i)
        new(address+i) T();
    }

    return address;
}

template<typename T>
void freeAddress(T* address){
    address->~T();
    freePointers.insert({(void*)address, sizeof(T)});
}

template<typename T>
void freeAddress(T* address, size_t count){
    for (size_t i = 0; i < count; ++i)
        address[i].~T();
    freePointers.insert({(void*)address, sizeof(T) * count});
}

#endif
std::vector

话虽如此,这不是一个非常安全或强大的内存分配器,但它应该可以帮助您入门。

如果确实要创建自定义内存分配器,则应编写遵循Allocator策略的类,然后可以将该分配器与标准C ++容器(例如public class SUT { public async Task Mut(object obj) { var x = await url1.PostJsonAsync(obj).ReceiveJson(); if ((bool)x.property = true) { var y = await url2.GetJsonAsync(); // Process y. } } } )一起使用。让编译器和标准库为您处理大部分艰苦的工作。

相关问题