编译器如何知道使用哪个操作符或函数分配了哪些内存



假设我为两个数组分配了内存,一个使用new操作符,另一个使用malloc函数。据我所知,这两个内存都是在堆段中分配的,那么我的问题是编译器如何知道哪个内存是使用哪个操作符或函数分配的?或者这背后还有其他的概念吗?

编译器不需要知道指针后面的内存是如何分配的,这是程序员的责任。您应该始终使用匹配的allocate-deallocate函数/操作符。例如,操作符new可以被重载。在这种情况下,当您使用new分配对象,并使用free()释放它时,您就遇到了麻烦,因为free()不知道您在那里有什么样的簿记。下面是这种情况的一个简化示例:

#include <iostream>
#include <stdlib.h>

struct MyClass
{
    // Really dumb allocator.
    static void* operator new(size_t s)
    {
        std::cout << "Allocating MyClass " << s << " bytes.n";
        void* res = Pool + N * sizeof(MyClass);
        ++N;
        return res;
    }
    // matching operator delete not implemented on purpose.
    static char Pool[]; // take memory from this statically allocated array.
    static unsigned N; // keep track of allocated objects.
};
char MyClass::Pool[10*sizeof(MyClass)];
unsigned MyClass::N = 0;
int main(int argc, char** argv)
{
    MyClass* p = new MyClass();
    if (argc == 1)
    {
        std::cout << "Trying to deleten";
        delete p; // boom - non-matching deallocator used.
    }
    else
    {
        std::cout << "Trying to freen";
        free(p); // also boom - non-matching deallocator used.
    }
}

如果您混合使用分配器和释放器,您将遇到类似的问题。

在内部,两种分配机制最终可能使用或不使用相同的机制,但是配对newfreemallocdelete会混合概念上不同的东西并导致未定义的行为。

不能用delete代替mallocfree代替new。尽管对于基本数据类型,您可以在大多数编译器上使用它,但它仍然是错误的。这并不能保证有效。mallocnew可以处理不同的堆,而不是同一个堆。此外,delete将调用对象的析构函数,而free不会。

编译器不必跟踪哪些内存块是由malloc或new分配的。它们可能是调试帮助,也可能不是。不要依赖它。

它不知道。它只是调用一个返回指针的函数,而指针并不携带它们是如何形成的或者它们指向什么样的内存的信息。它只是传递那个指针,不再关心它。

然而,你用来释放内存的函数(即free/delete)可能依赖于存储在malloc/new隐藏的地方的信息。因此,如果您通过malloc分配内存,并尝试通过delete(或newfree)来释放内存,则可能无法工作(除了构造函数/析构函数的明显问题)。

可能不起作用在这种情况下没有定义发生了什么。这对编译器开发人员和性能来说是一个巨大的好处,因为他们根本不需要关心。另一方面,开发人员必须跟踪特定内存的分配情况,这就把工作推给了开发人员。最简单的方法是只使用两种方法中的一种。

  • new/delete是c++中分配内存和从堆中释放内存的方法

  • malloc/free/family是从堆中分配和释放内存的C方式

我不知道为什么你想让编译器知道谁分配了堆内存,但是如果你想要追踪是有办法的。

这样做的一种方法是new将通过调用构造函数来初始化分配的内存,您可以监视该构造函数以知道谁将内存分配给堆。

问候,yanivx

据我所知,这两个内存都是在堆段中分配的,那么我的问题是编译器如何知道哪个内存是使用哪个操作符或函数分配的?

你所谓的"堆段"是什么?

就C和c++标准而言,没有这样的事情。"堆"one_answers"堆栈"是特定于实现的概念。它们是非常广泛使用的概念,但标准都没有强制要求使用"堆"或"堆栈"。

实现(而不是编译器!)如何知道东西分配到哪里取决于实现。你最好的选择,也是唯一安全的选择,就是按照标准的要求去做:

  • 如果你使用new[]分配内存,你必须使用delete[]释放它(或者不删除它)。

  • 如果你使用new分配内存,你必须使用delete释放它(或者不删除它)。

  • 如果你使用malloc或它的同类分配内存,你必须使用free来释放它(或保留它不被删除)。


不释放已分配的内存有时可能是一个严重的问题。如果您不断地分配大块内存而从不释放单个内存,那么您将遇到问题。其他时候,这根本不是问题。在程序开始时分配一块内存,哎呀,你没有释放它通常不是问题,因为分配的内存在程序结束时被释放。这些内存泄漏是否真的是一个问题,这取决于您。

避免这些更大的问题的最简单的方法是让程序在退出之前适当地释放分配的内存的每个字节。

注意:这样做并不能保证你没有内存问题。仅仅因为您的程序最终应该释放在程序执行过程中分配的多个tb中的每一个,并不一定意味着程序在内存方面是好的。

相关内容

  • 没有找到相关文章

最新更新