我有一个生成最终结果和一些中间结果的函数"管道"。我正在寻找一种方法,通过清理中间结果,一旦他们不再需要减少峰值内存。
如果我不关心中间结果的内存,这就是它的样子。B、C、D、E和F都是std
容器,每个容器都有超过一百万的对象。
void A::getF(F &f) {
B b;
C c;
computeBAndC(b, c);
D d;
computeD(b, c, d);
// b and c no longer needed
E e;
computeE(d, e);
// d no longer needed
computeF(e, f);
}
这些是我想到的方法:
。一旦不再需要,使用new
和delete
进行清理。但是,对std容器使用new和delete有意义吗?
void A::getF(F &f) {
B *b = new B;
C *c = new C;
computeBAndC(b, c);
D *d = new D;
computeD(b, c, d);
// b and c no longer needed
delete b;
delete c;
E e;
computeE(d, e);
// d no longer needed
delete d;
computeF(e, f);
}
B。使用std容器的swap
函数在使用后清除其内存
void A::getF(F &f) {
B b;
C c;
computeBAndC(b, c);
D d;
computeD(b, c, d);
// b and c no longer needed
B().swap(b);
C().swap(c);
E e;
computeE(d, e);
// d no longer needed
D().swap(d);
computeF(e, f);
}
C。使用块。
void A::computeF(F &f) {
E e;
{
D d;
{
B b;
C c;
computeBAndC(b, c);
computeD(b, c, d);
// b and c no longer needed
}
computeE(d, e);
// d no longer needed
}
computeF(e, f);
}
D。重新构造,以便在函数作用域结束时删除中间结果:
void A::getF(F &f) {
E e;
getE(e);
computeF(e, f);
}
void A::getE(E &e) {
D d;
getD(d);
computeE(d, e);
}
void A::getD(D &d) {
B b;
C c;
computeBAndC(b, c);
computeD(b, c, d);
}
这些方法的优缺点是什么?这些真的会降低内存使用峰值吗?有没有更好的办法?
老实说,我会选择选项D,因为考虑到您的一些变量之间存在一些联系,将这些代码提取到函数中不仅可以解决您的内存问题,而且还可以更好地记录您使用代码本身的意图(我相信您可以在代码中提出良好的自解释名称)。唯一的问题当然是性能,如果你使用一个更好的方法来函数签名(假设你不控制compute
函数:即
E A::computeE(const D& d) {
E e;
computeE(d, e);
return E;
}
我从你的评论中了解到你只能使用没有移动语义的c++ 98。然而,编译器长期以来一直能够执行命名返回值优化-在您的情况下,我会尝试测试您的编译器使用NRVO(和复制省略)的能力,如果它是好的-使用我概述的更自然的(IMO)签名-否则我会使用您的选项d
如果您在这些容器中存储指向对象的指针,那么删除它们(或者只是让它们超出作用域)不会释放对象正在使用的内存,只会释放容器本身的内存。您还必须删除容器中的每个对象。
否则,在STD容器上使用new和delete是完全有意义的。这也意味着在堆上而不是堆栈上为它们分配内存,这可能是明智的,因为虽然堆栈有利于快速分配,但如果在堆栈上转储太多,可能会耗尽内存。您可能还会遇到分页问题。
然而,要真正解决你的问题,更多地了解你在做什么会有所帮助。你真的需要使用性病容器吗?你能用数组代替吗?容器中的对象对每个容器来说是唯一的吗,还是它们是被重新安排到不同容器中的同一堆对象?有没有办法把操作分解成更小的数据集,而不是像那样在一系列容器中运行?