使用new实例化类时。而不是删除内存我们将基于对象的重用获得什么样的好处?
新的过程是什么?是否发生了上下文切换?分配了新内存,谁在进行分配? OS?
答案 0 :(得分:5)
你在这里问过几个问题......
而不是删除内存而不是基于对象的重用会获得什么样的好处?
这完全取决于您的申请。即使假设我知道应用程序是什么,你还没有指定另一个细节 - 你重复使用的策略是什么?但即使知道这一点,也很难预测或回答一般问题。尝试一些事情并测量它们。
根据经验,我喜欢尽量减少最无偿的分配。不过,这主要是过早的优化。它只会对成千上万的电话产生影响。
新的过程是什么?
完全依赖于实现。但是,分配器使用的一般策略是拥有一个空闲列表,即一个已在过程中释放的块列表。当空闲列表为空或包含不足的连续空闲空间时,它必须向内核询问内存,它只能以常量页面大小的块给出。 (x86上的4096.)分配器还必须决定何时切断,填充或合并块。多线程也会对分配器施加压力,因为它们必须同步它们的空闲列表。
一般来说,这是一项非常昂贵的操作。相对于你正在做的其他事情,可能没那么多。但它并不便宜。
是否发生了上下文切换?完全可能。它也有可能不会。你的操作系统可以在任何时候获得中断或系统调用时自由进行上下文切换,所以呃......这种情况很多时候都会发生;我没有看到它和你的分配器之间有任何特殊的关系。
分配了新内存,谁在进行分配? OS?它可能来自空闲列表,在这种情况下不涉及系统调用,因此操作系统没有帮助。但如果空闲列表无法满足请求,它可能来自操作系统。此外,即使它来自空闲列表,您的内核可能已经分页了这些数据,因此您可能会在访问时出现页面错误,并且内核的分配器会启动。所以我想这将是一个混合包。当然,你可以有一个符合要求的实现,可以做各种疯狂的事情。
答案 1 :(得分:2)
通常,c ++运行时使用操作系统内存管理功能分配大块内存,然后使用自己的堆实现对其进行细分。 microsoft c ++运行时主要使用在usermode中实现的Win32堆函数,并使用虚拟内存apis划分分配的OS内存。因此,除非需要当前分配虚拟内存,否则不需要上下文切换,并且需要转到操作系统来分配更多内容。
在分配内存时存在一个理论问题,即堆遍历可能需要多长时间才能找到空闲块。实际上,堆分配通常很快。
除了线程应用程序。由于大多数c ++运行时在多个线程之间共享一个堆,因此需要序列化对堆的访问。这可能严重降低某些类别的应用程序的性能,这些应用程序依赖于多个线程能够新建和删除许多对象。
答案 2 :(得分:1)
如果您new
或delete
地址标记为已占用或未分配。实现不会一直与内核进行通信。更大的内存量保留在应用程序的用户空间中的较小的卡盘中。
由于new
和delete
是可重入(或线程安全,具体取决于实现),可能会发生上下文切换,但您的实现仍然是线程安全的使用默认的new
和delete
。
在C ++中,您可以覆盖new
和delete
运算符,例如放置你的记忆管理:
#include <cstdlib> //declarations of malloc and free
#include <new>
#include <iostream>
using namespace std;
class C {
public:
C();
void* operator new (size_t size); //implicitly declared as a static member function
void operator delete (void *p); //implicitly declared as a static member function
};
void* C::operator new (size_t size) throw (const char *){
void * p = malloc(size);
if (p == 0) throw "allocation failure"; //instead of std::bad_alloc
return p;
}
void C::operator delete (void *p){
C* pc = static_cast<C*>(p);
free(p);
}
int main() {
C *p = new C; // calls C::new
delete p; // calls C::delete
}