2011-04-09 141 views
-1

我正在處理運行時new在程序仍然需要內存時的失敗。我不想讓程序停下來。那麼無論如何要重新分配?提前致謝!新的和malloc(C++)未能分配內存。如何修復/重新分配?

+1

你能解釋得更好嗎? – 2011-04-09 05:58:41

+0

你的程序真的需要比你的機器上更多的內存嗎?如果確實如此,那麼如果你無法獲得更多的信息,那麼很難繼續,如果它實際上並不需要它,也許你實際上並不需要遇到'new'的失敗。 – Cascabel 2011-04-09 06:08:21

+0

這取決於你需要多少額外的內存(會有固定的數量嗎?),以及是否有可能釋放任何現有的分配。這種情況並不常見,因爲大多數現代操作系統會過度使用內存,這通常會導致系統逐漸放緩,甚至在發生'throw bad_alloc'之前崩潰。 – Potatoswatter 2011-04-09 06:09:56

回答

0

你可以就在年初

FixedMemory<1024> fMem(4); // memsize 1024Char 
FixedHeap<1024,16> fHeap(fMem); // 1KiB/ 16Byte = 64 Blocks 

// if usual allocation fails: 
ptr = (ptrdiff_t) fHeap.alloc(16);// sizeof(Foo) 
Foo* foo = new (ptr) Foo(); 
// make sure that Foo does not call new/malloc/... 
// or you have to handle that as well 
foo->~Foo; 
fHeap.free(pMem); 

當然預留用於緊急用途的大型靜態存儲器塊,那麼你必須實現自己的內存管理。你寫你自己的堆類如下界面:

class Heap { 
protected: 
    /** Initializes reference to system memory.*/ 
    Heap(Memory& memory) : memory(memory) 
    { 
    } 

public: 
    /** Allocate a piece of memory. 
    * @param size size of the memory to allocate 
    * @return pointer to allocated memory or null on error 
    */ 
    virtual void* alloc(size_t size)=0; 

    /** Free previously allocated memory. 
    * @param p pointer to the memory to free 
    */ 
    virtual void free(void* address)=0; 

private: 
    /** Reference to the system memory source. */ 
    Memory& memory; 
}; 

最簡單的實現將是一個固定堆,只返回一個固定長度的指針segmens(或空指針,如果你試圖獲得更多)。這是可以的,如果你已經知道你需要分配的最大尺寸(sizeof(ClassToWorkWith))。

然後您需要固定的內存:

template<size_t MEMSIZE> 
class FixedMemory { 
private: 
    char MemArray[MEMSIZE]; 
    const size_t alignment;  
public: 
    FixedMemory(size_t alignment) : alignment(alignment) 
    { 
    } 

    void * GetMemory() 
    { 
     return (void*)((char*)MemArray); 
    } 
}; 

然後你就可以實現一個固定堆基本上是這樣的

template<size_t MEMSIZE, size_t BLOCKSIZE> 
class FixedHeap : public Heap { 
private: 
    void *FreeHead; 
    size_t realBlockSize; 

public: 
    FixedHeap(Memory& memory) : Heap(memory), FreeHead(0) 
    { 
      realBlockSize = BLOCKSIZE; 
      if(memory.alignment < sizeof(void*))return; 
      if(realBlockSize < sizeof(void*))realBlockSize = sizeof(void*); 
      realBlockSize += (BLOCKSIZE%memory.alignment) ? (memory.alignment - BLOCKSIZE%memory.alignment) : 0; 
      if(MEMSIZE >= realBlockSize) { 
        char *pMemory = (char *)memory.GetMemory(); 
        size_t malAlignment = (memory.alignment - (size_t)pMemory%memory.alignment)%memory.alignment; 
        size_t actualMemSize = MEMSIZE - malAlignment; 
        pMemory += malAlignment; 

        for(size_t i=0; i<actualMemSize/realBlockSize-1; i++) 
        { 
          *((ptrdiff_t *)(&pMemory[i*realBlockSize])) = (ptrdiff_t)&pMemory[(i+1)*realBlockSize]; 
        } 

        *((ptrdiff_t *)(&pMemory[(actualMemSize/realBlockSize-1)*realBlockSize])) = 0; 
        FreeHead = (void *)pMemory; 
      } 
    } 

    void* alloc(size_t size) 
    { 
      if(size > BLOCKSIZE || !FreeHead) return 0; 
      void *Result = FreeHead; 
      FreeHead = (void *)*((ptrdiff_t *)FreeHead); 
      return Result; 
    } 

    void free(void* address) 
    { 
      if(address && (! address % realBlockSize)) { 
        *((ptrdiff_t *)address) = (ptrdiff_t)FreeHead; 
        FreeHead = address; 
      } 
    } 
}; 

有一些更好的替代品,像FirstFitHeap但我只是想給你一個提示。

+0

你能解釋一下嗎? – user699673 2011-04-09 06:05:38

2

您可以在不需要時暫時將對象存儲到磁盤,並在需要訪問它們時重新加載它們。例如Photoshop曾經擁有它自己的交換文件IIRC。但是,滾動你自己的基於文件的對象存儲並不容易 - 不確定是否有適當的實現已經存在。

另一方面,在你問這個問題的方式中,你似乎意外地耗盡了內存 - 所以你可能已經在你的應用程序設計中遇到了某種問題,並試圖修復症狀而不是原因不是必然是最好的行動方針。

2

請提供更多詳情。

從你給出的描述中,我假設你的程序會拋出內存分配錯誤。 按照這種模式,至少在內存不足情況下能夠正常退出。

  1. 在程序開始之前保留一些內存。 炭reserveMemory =新的char [1024 * 1024] // 1Mb的

  2. 寫一個函數在內存不足的情況下,解除該存儲器,並將其設置爲new_handler(檢查set_new_handler()是一個好的C++書)。

  3. 在您釋放reserveMemory之後,您的堆上有1 MB的內存。這取決於你的技能,利用這個內存退出,或通過釋放堆中的不需要的對象等來恢復更多內存。

+0

作爲評論會更好。 – dmckee 2011-04-09 18:57:18