(请原谅我这个问题是否重复,我是初学者,不知道要搜索哪些条款才能找到答案!)
我正在尝试为c ++编写一个带有一些非常基本的内存管理的线性代数库 - 主要是使用shared_ptrs;一旦ptr计数达到0,它就会将内存返回给管理器。 我正在处理的数组的大小非常大,而且内存非常宝贵,所以我试图强制代码尽快触发清理冗余内存变量。
考虑:
a,b,c,d,e不是临时变量,每个约5GB。
z = a + b + c + d + e
或者
z = add(a,add(b,add(c,add(d,e)))) - 这就是我到目前为止实际编码的方式,没有操作符过载。
我发现一旦相等操作完成,临时变量(每个操作一个)只会超出范围,因此shared_ptr仍然认为内存正在使用中。结果,刮擦空间的清理一下子发生,理论上,单个存储器块保持在&#d; d + e'可能会被扔掉一次&#c; c + d + e'存储,等等。
显然这会导致内存使用量大幅增加,因为在使用的临时空间中不是5GB,而是需要20GB。
要解决这个问题,我必须做以下事情
z = d + e
z = c + z
z = b + z
z = a + z
这允许先前的临时变量超出每个新行的范围,但它会在我的代码的几个部分中引起一些非常讨厌的膨胀。
有没有办法强制代码在行尾之前将临时内存返回给管理器?我认为我可以对共享指针做些什么,或者通过引用而不是值传递,但我不能完全指责它。
澄清一下,我在寻找什么:
为(d + e)分配内存,执行计算
为(c + d + e)分配内存,执行计算,释放(d + e)
为(b + c + d + e)分配内存,执行计算,释放(c + d + e)
为(a + b + c + d + e)分配内存,执行计算,释放(b + c + d + e)
将(a + b + c + d + e)指针指向z
#include <iostream>
class Foo {
public:
int fooid;
Foo(int fi) {
fooid = fi;
std::cout << "Creating array " << fooid << std::endl;
}
~Foo() {
std::cout << "Cleanup array " << fooid << std::endl;
}
};
Foo mult(const Foo &a, const Foo &b)
{
//std::cout << "Constructing new foo" << std::endl;
Foo out(a.fooid*b.fooid);
return out;
}
int main()
{
Foo twos(2); //placeholders for huge non-temporary arrays
Foo threes(3);
Foo fives(5);
Foo sevens(7);
Foo elevens(11);
std::cout <<"Method 1" << std::endl;
Foo vx = mult(mult(mult(mult(twos,threes), fives),sevens),elevens);
//std::cout << vx.fooid << std::endl;
//system("pause");
std::cout << std::endl <<"Method 2" << std::endl;
//Alternative, over 3 lines, forces destructors earlier than above, more scratch space for the later operations
//Note array 30 is deleted before array 210 is constructed, unlike Method 1
Foo vx1 = mult(twos, threes);
vx1 = mult(vx1, fives);
vx1 = mult(vx1, sevens);
vx1 = mult(vx1, elevens);
std::cout << std::endl <<"End" << std::endl;
return 0;
}
输出如下:
Creating array 2
Creating array 3
Creating array 5
Creating array 7
Creating array 11
Method 1
Creating array 6
Creating array 30
Creating array 210
Creating array 2310
Cleanup array 210
Cleanup array 30
Cleanup array 6
Method 2
Creating array 6
Creating array 30
Cleanup array 30
Creating array 210
Cleanup array 210
Creating array 2310
Cleanup array 2310
End
Cleanup array 2310
Cleanup array 2310
Cleanup array 11
Cleanup array 7
Cleanup array 5
Cleanup array 3
Cleanup array 2
上述方法之间的主要区别在于方法2能够在执行下一步计算之前释放旧的临时变量,而第一种方法在计算完全完成之前保留其所有内存。我希望找到一种方法,我可以获得方法2的结果,同时按照方法1的方式进行编码。
很抱歉经常编辑。想要做对。
答案 0 :(得分:0)
简单的答案,从C ++ 11开始(至少部分由之前的优秀编译器实现)是通过 value 接受你的参数。这似乎违反直觉,因为它听起来像更多副本,但实际上现有数据的所有权通过移动构造函数(和/或编译器魔术)传递到函数中。
然后,您更新“到位”的“副本”并将其返回,以便将其资源转移到另一个函数调用中以便重复使用/更新再次。在完整表达式结束时,将运行几个析构函数(由于“强制copy elision”,每个函数返回时,C ++ 17 可能运行它们,但大多数将用于移动 - 来自资源已经被重用和/或释放的对象。
当然,等大小参数的每个函数最多需要一个来存储其结果;由于大多数运算符都是左关联的,因此by-value参数的明显选择是第一个。您可以使用值传递的第二个操作数定义减法的变量,以捕获z=a-(b*c)
等案例。
答案 1 :(得分:0)
我正在尝试编写一个线性代数库,其中包含一些 C ++的基本内存管理-基本上使用shared_ptrs; 一旦ptr计数达到0,它将把内存返回给管理器。
...
a,b,c,d,e不是临时变量,每个〜5GB。
如果您要创建a linear algebra library
来练习编程技能,那就好。
但是您已经写过variables, ~5GB each
了!这意味着您正在解决一些严重的问题。如果您是我,则可以使用现成的库gmp
。原因很简单。这个库由许多聪明的人创建和优化了数千个小时。这样,您可以从“等式”中消除一个问题。
矩阵的大小非常大,建议您应该阅读的另一件事是sparse matrix。这样做可能会使您的数据更紧凑,并加快计算速度。
当您使用库时,清除已使用的变量的内存将非常简单(调用一些名为clean
之类的函数)。这样您的问题就不会成为问题。
我怀疑您的问题是XY problem,请考虑提供更多不那么笼统的信息