我正在用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
我知道我无法删除堆栈存储器上的指针,但是我根本没有使用它。另外请指出我做错了什么还是性能有所提高。请帮忙。
答案 0 :(得分:3)
您使用line.set_xdata((x1, Bx))
line.set_ydata((y1, By))
分配了一大块内存,然后在某个指针上调用malloc
进入已分配的内存。
在您的代码中,delete
是q
。该指针从未由分配返回,因此无法释放。这就是错误的原因。
此外,将(memory + sizeof(int))
与malloc
不匹配是未定义的行为。最后,您应该在原始delete
指针上调用free()
作为清除,并且永远不要在单个值上调用memory
。
如果要在delete
中调用析构函数,请使用freeAddress
。
答案 1 :(得分:0)
您一次在initMemory()
中分配了一个1字节的内存块。您正在使用malloc()
进行该分配,因此在完成使用free()
时必须使用freeAddress()
释放内存块,但是您没有这样做。
您的delete
是new
的内存,从未分配过allocate()
。在new
内部,您使用的是 placement-new 而不是free()
,它们不是同一回事。使用 placement-new 时,您必须手动调用对象的析构函数,而不是delete
或new[]
。
您当然不希望释放以后将要重用的内存。这样就无法达到缓存“已释放”内存的全部目的。
并且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.
}
}
}
)一起使用。让编译器和标准库为您处理大部分艰苦的工作。