2013-06-04 52 views
8

我目前用約2.5GB值得的存儲器非常大的數據集的工作..std :: vector交換導致內存碎片?

我目前使用包含 1)元數據 2)boost::ptr_list<MemoryBlock>

類數據的矢量存儲該該MemoryBlock中類包含 1)元數據 2)std::vector<XYZ>

填充的時候,我保留我的std::vector<xyz> 50,000組。如果我的矢量的空間尺寸變大,我會創建一個新的內存塊,並使用它來將矢量縮小到適當的大小。

現在的問題... 看來,當我使用交換技巧來調整我的數組大小時,我開始運行到std :: bad_alloc異常後清除所有的數據並加載到一個新的數據集。

我可以加載的數據量急劇減少......每次清除我的數據並加載到新的數據集時,它都會繼續這樣做......例如,我的初始數據集將加載億個價值觀

下一次它會加載50000000個值

下次70000000個值

下一次

20000000個值 等等

我首先想到的是內存泄漏,但有沒有什麼我能夠識別的。代碼中除了交換之外的所有東西都被廣泛使用了很長時間,沒有任何問題。

如果我不使用交換/空間維度檢查,一切都會繼續並正常工作。

任何想法?!?

編輯

bool Check_MemBlock_Size(MemoryBlock &CurrMemblock, XYZ CheckPoint){ 

    // Set a minimum of 5000 points in each memory block regardless of physical size.. 
    if(CurrMemblock.PointsArr.size() > 5000){ 
     XYZ TestMin, TestMax; 
     TestMin = CurrMemblock.Min; 
     TestMax = CurrMemblock.Max; 

     // Check what the bounding box would be if we included the check point.. 
     if(TestMax.x < CheckPoint.x) 
      TestMax.x = CheckPoint.x; 
     if(TestMax.y < CheckPoint.y) 
      TestMax.y = CheckPoint.y; 
     if(TestMax.z < CheckPoint.z) 
      TestMax.z = CheckPoint.z; 

     if(TestMin.x > CheckPoint.x) 
      TestMin.x = CheckPoint.x; 
     if(TestMin.y > CheckPoint.y) 
      TestMin.y = CheckPoint.y; 
     if(TestMin.z > CheckPoint.z) 
      TestMin.z = CheckPoint.z; 

     // If the new bounding box is too big, lets break it off. 
     if(fabs(TestMax.x - TestMin.x) > 100 || fabs(TestMax.y - TestMin.y) > 100 || fabs(TestMax.z - TestMin.z) > 50){ 

      std::vector<XYZ>(CurrMemblock.PointsArr).swap(CurrMemblock.PointsArr); 

      return false; 

     } 
    } 


    return true; 
} 

下面是使用這個代碼段..

    if(Check_MemBlock_Size(*MemBlock, NewPoint) == false){ 

         Data->MemoryBlocks.push_back(MemBlock); 

         try { 
          MemBlock = new MemoryBlock(); 
         } catch (std::bad_alloc) { 
          printf("Not enough memory\n"); 
          delete Buffer; 
          break; 
         } 

         BlockSize = 0; 

         try{ 
          MemBlock->PointsArr.reserve(MaxBlockSize); 
         } catch(std::bad_alloc){ 
          delete MemBlock; 
          delete Buffer; 
          printf("Not enough memory\n"); 
          break; 
         } 

        } 


        // Push the point to our current memory block 
        BlockSize++; 
        MemBlock->PointsArr.push_back(NewPoint); 

        .... // More stuff going on here.. irrelevant 

        // push a new memory block if we hit the block point limit. 
        if(BlockSize >= MaxBlockSize){ 

         Data->MemoryBlocks.push_back(MemBlock); 

         try { 
          MemBlock = new MemoryBlock(); 
         } catch (std::bad_alloc) { 
          printf("Not enough memory\n"); 
          delete Buffer; 
          break; 
         } 

         BlockSize = 0; 

         try{ 
          MemBlock->PointsArr.reserve(MaxBlockSize); 
         } catch(std::bad_alloc){ 
          printf("Not enough memory\n"); 
          delete MemBlock; 
          delete Buffer; 
          break; 
         } 

        } 
+3

每個內存分配都有可能導致內存碎片。 – PlasmaHH

+1

我認爲C++ 11 vector :: shrink_to_fit和移動構造函數(而不是在增長時複製)可以緩解您的問題。選擇C++ 11嗎? – mirk

+0

C++ 11不是一個選項。我知道每個分配都會導致一些分裂,但不是我看到的程度。 – user1000247

回答

6

這種技術似乎保證碎裂如果之間調用Check_MemBlock_Size()你做一些更多的動態分配。這是因爲您在分配較小的塊後釋放您的50K分配,在內存中創建一個50K的對象空洞,現在可以部分填充更多內存,您的下一個MemoryBlock重建將無法使用。

您可以創建一個全局向量而不是暫時的向量來存放這個50K對象分配。然後,當你下一次重建一個新的MemoryBlock,而不是調整一個新的50K對象矢量,只需交換全局。當你想縮小它時,再次用全球換掉。以這種方式重新使用50K保留內存將刪除此分配可能產生的任何碎片。

但是,如果您確定沒有泄漏,則在程序中可能存在其他碎片來源。通常情況下,碎片是由動態分配的大小對象組成的,每個對象都有不同的生命週期。解決這個問題有很多方法,但處理它的一種方法是使用內存池。從這個意義上說,池是一組相同大小和相同生命週期的對象的集合,它們組合在一個自定義分配器中。這種內存的取消分配將返回到其池中。如果內存永遠不會返回到使用delete的系統,則該池通過允許將來的分配重新使用先前爲相同對象類型分配的內存來對抗分段。這些池的運行時間利用率達到峯值,碎片永遠不會比這更糟糕。

+0

謝謝!這聽起來像它可能工作。我會試一試 – user1000247

+0

這沒有工作:( – user1000247

+0

@ user1000247:你是什麼意思? – jxh