[英]Memory optimization in huge data set
不好意思,我已經實現了一些功能,並且想問一些基本的問題,因為我對C ++沒有足夠的基礎知識。 希望大家能告訴我什么是應該向我學習的好方法。 (拜托,這不是功課,我沒有專家請我回答這個問題)
我所做的是 我從文件中讀取輸入的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;
}
代碼03
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);
}
對於如此龐大的數據集,我將完全避免使用std容器,而使用內存映射文件。
如果您希望繼續使用std :: vector,請使用vector::clear()
或vector::swap(std::vector())
釋放已分配的內存。
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中,調用者可以播放一個稱為“ swaptimization”的技巧。 代替:
vector<Position3D> foo;
// some other use of foo
foo = ReturnLabel();
寫:
vector<Position3D> foo;
// some other use of foo
ReturnLabel().swap(foo);
3)您編寫的函數簽名更加復雜,例如通過非常量引用獲取vector
並將其填充到其中,或者將OutputIterator作為模板參數。 后者還為調用者提供了更大的靈活性,因為他們不需要使用vector
來存儲結果,因此他們可以使用其他容器,甚至一次處理一個容器而無需一次存儲整個容器。
您的代碼看起來像是第一個循環中的計算值僅在第二個循環中上下文無關地使用。 換句話說,一旦在第一個循環中計算了double值,就可以立即對其執行操作,而無需一次存儲所有值。
如果是這樣,您應該以這種方式實現。 不用擔心大的分配,存儲或其他任何事情。 更好的緩存性能。 幸福。
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);
如果“結果”向量最終將具有數千個值,則將導致許多重新分配。 最好用足夠大的容量來初始化它,或者使用reserve函數:
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
您返回引用的想法是正確的,因為您要避免復制。
`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)
代碼1可以正常工作,並且幾乎與代碼2相同,沒有主要優點或缺點。
code03其他人應該回答,但是我相信在這種情況下指針和引用之間的區別很小,不過我確實更喜歡指針。
話雖如此,我認為您可能會從錯誤的角度進行優化。 您是否真的需要所有點來計算第一個循環中點的輸出? 還是可以重寫算法以僅讀取一個點,像在第一個循環中那樣計算值,然后以所需方式立即使用它? 也許不是單點,而是成批的點。 這可能會減少您的內存需求,而處理時間只增加一點點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.