2011-11-21 143 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)