2011-11-21 158 views
0

交易全部,我已经实现了一些功能,并喜欢问一些基本的事情,因为我没有一个在C + +的基础知识。我希望,大家都会友好地告诉我,我可以从你身上学到什么样的好方法。 (拜托,这不是一门功课,我DONOT有任何专家角落找寻我问这个)庞大的数据集内存优化

我做什么;我从文件中读取输入x,y,z点数据(大约3GB数据集),然后为每个点计算一个单一值并存储在一个向量(结果)中。然后,它将在下一个循环中使用。然后,该向量将不再使用,我需要获取该内存,因为它包含巨大的数据集。我认为我可以通过两种方式做到这一点。 (1)通过初始化矢量,稍后擦除它(参见代码-1)。 (2)通过分配动态内存然后解除分配(见代码2)。我听说这种解除分配是无效的,因为解除分配又花费了内存,或者我误解了。

Q1) 我想知道什么是在内存和效率方面的优化方式。

Q2) 另外,我想知道引用函数返回是否给予输出的好方法。 (请看码-3)

代码-1

int main(){ 

    //read input data (my_data) 

    vector<double) result; 
    for (vector<Position3D>::iterator it=my_data.begin(); it!=my_data.end(); it++){ 

     // do some stuff and calculate a "double" value (say value) 
     //using each point coordinate 

     result.push_back(value); 

    // do some other stuff 

    //loop over result and use each value for some other stuff 
    for (int i=0; i<result.size(); i++){ 

     //do some stuff 
    } 

    //result will not be used anymore and thus erase data 
    result.clear() 

代码-2

int main(){ 

    //read input data 

    vector<double) *result = new vector<double>; 
    for (vector<Position3D>::iterator it=my_data.begin(); it!=my_data.end(); it++){ 

     // do some stuff and calculate a "double" value (say value) 
     //using each point coordinate 

     result->push_back(value); 

    // do some other stuff 

    //loop over result and use each value for some other stuff 
    for (int i=0; i<result->size(); i++){ 

     //do some stuff 
    } 

    //de-allocate memory 
    delete result; 
    result = 0; 
} 

code03

vector<Position3D>& vector<Position3D>::ReturnLabel(VoxelGrid grid, int segment) const 
{ 
    vector<Position3D> *points_at_grid_cutting = new vector<Position3D>; 
    vector<Position3D>::iterator point; 

    for (point=begin(); point!=end(); point++) { 

     //do some stuff   

    } 
    return (*points_at_grid_cutting); 
} 

回答

1

erase自由存储器用于矢量。它减小了尺寸,但不是容量,所以这个矢量对于所有这些双打仍然拥有足够的内存。

,使再次可用内存的最好办法是像你的代码-1,但让矢量超出范围:

int main() { 
    { 
     vector<double> result; 
     // populate result 
     // use results for something 
    } 
    // do something else - the memory for the vector has been freed 
} 

如果做不到这一点,惯用的方法来清除一个载体和释放内存是:

vector<double>().swap(result); 

这将创建一个空的临时载体,然后将其与result交换的所述内容(因此result是空的并具有小的容量,而临时拥有所有数据和大容量)。最后,它破坏了临时性,并带走了大量缓冲区。

关于code03:这不是好作风参考返回一个动态分配的对象,因为它不提供呼叫者与多提醒他们是负责释放它的。经常做的最好的事情是按值返回一个局部变量:

vector<Position3D> ReturnLabel(VoxelGrid grid, int segment) const 
{ 
    vector<Position3D> points_at_grid_cutting; 
    // do whatever to populate the vector 
    return points_at_grid_cutting; 
} 

的原因是,所提供的呼叫者使用调用这个函数作为初始化为自己的向量,则叫做“命名返回值优化“踢进来,并确保尽管你按价值归还,但没有价值的副本。

没有实现NRVO的编译器是一个糟糕的编译器,可能会出现各种其他令人惊讶的性能故障,但有些情况下NRVO不适用 - 最重要的是,当该值分配给由调用者变量而不是在初始化中使用。有三种解决方法:

1)C++ 11引入了移动语义,基本上通过确保临时分配很便宜来对其进行分类。

2)在C++ 03中,调用者可以发挥一种称为“互换优化”的技巧。代替:

vector<Position3D> foo; 
// some other use of foo 
foo = ReturnLabel(); 

写:

vector<Position3D> foo; 
// some other use of foo 
ReturnLabel().swap(foo); 

3)你写一个函数具有更复杂的签名,例如通过非const引用采取vector以及填充值成,或采取一个OutputIterator作为模板参数。后者还为呼叫者提供了更大的灵活性,因为他们不需要使用vector来存储结果,他们可以使用其他容器,或者一次处理一个容器,而不一次存储整个容器。

+0

另一个想法可能是使用'deque'而不是'vector',因为存储的连续性似乎不是OP的要求。 –

+0

同意。这可能会很快加速建立容器的过程,所有这些'push_back'调用都可以帮助解决这个问题,并且可能有助于系统有3GB可用内存的(不常见)情况,但不能连续分配它,因此不能将其用于矢量。 –

+0

另一种加速所有'push_back'的可能方法是以'results.reserve(my_data.size());' –

2

对于这样庞大的数据集,我会避免使用std容器,并使用内存映射文件。

如果您喜欢继续使用std :: vector,请使用vector::clear()vector::swap(std::vector())来释放分配的内存。

+1

'swap'调用不起作用,因为它需要一个非常量引用。 –

+0

@Kerrek SB:我没有得到你。在问题和示例中const没有任何内容,事实上,在许多std容器实现中,clear()是在swap()的帮助下实现的。 –

+1

@Kirill:'std :: vector ()'是一个临时对象。它不能绑定到非const引用。 'vector :: swap'的参数是一个非const引用。因此,你不能写'myvector.swap(std :: vector ());' –

1

您的代码看起来像第一个循环的计算值仅在第二个循环中使用上下文不敏感。换句话说,一旦在第一个循环中计算了double值,您就可以立即采取行动,而无需一次存储所有值。

如果是这样,你应该这样实现它。不用担心大的分配,存储或任何事情。更好的缓存性能。幸福。

+0

我认为这无疑是最好的主意。当然,在C++中使用'iterator'并不像其他环境中那样糖涂层,但它是数据流的基本概念。 –

-1

code-1可以正常工作,并且与代码2几乎相同,没有什么大的优点和缺点。

code03别人应该回答,但我相信在这种情况下指针和引用之间的区别将是边缘的,我更喜欢指针。

这就是说,我认为你可能会从错误的角度接近优化。你真的需要所有的点来计算第一个循环中一个点的输出吗?或者,您是否可以重写算法以只读取一个点,像在第一个循环中那样计算该值,然后按照您希望的方式立即使用它?也许不是单点,而是分批次。这可能会削减你的内存需求相当多,处理时间只有很小的增加。

+0

code03会产生相当严重的内存泄漏。 – thiton

0
vector<double) result; 
    for (vector<Position3D>::iterator it=my_data.begin(); it!=my_data.end(); it++){ 

     // do some stuff and calculate a "double" value (say value) 
     //using each point coordinate 

     result.push_back(value); 

如果“结果”向量最终将有成千上万的值,这将导致许多重新分配。

vector<double) result (someSuitableNumber,0.0); 

这将减少重新分配的数量,并可能进一步优化您的代码:如果你有足够大的容量来存储,或使用储备功能初始化,那将是最好的。

而且我会写:vector<Position3D>& vector<Position3D>::ReturnLabel(VoxelGrid grid, int segment) const

像这样:

void vector<Position3D>::ReturnLabel(VoxelGrid grid, int segment, vector<Position3D> & myVec_out) const //myVec_out is populated inside func 

你返回一个参考的思路是正确的,因为你要避免复制。

0

`C++中的析构函数不能失败,因此解除分配不会分配内存,因为无法保证无法分配内存。

除了多次循环之外,如果以集成方式执行操作(即不是加载整个数据集,然后减少整个数据集,只是逐个读取点),而是多次循环直接申请减少,即代替

load_my_data() 
for_each (p : my_data) 
    result.push_back(p) 

for_each (p : result) 
    reduction.push_back (reduce (p)) 

只是做

file f ("file") 
while (f) 
    Point p = read_point (f) 
    reduction.push_back (reduce (p)) 

如果你不需要保存这些削减,只是它们输出顺序

file f ("file") 
while (f) 
    Point p = read_point (f) 
    cout << reduce (p)