如何渡過內存危機(轉)

關於OOM(Out Of Memory),  這個在嵌入開發中定期和不定期都會出現的危機。

講兩件事情:第一件是我們必須做到的,不然OOM來襲會造成程序崩潰,第二件是我們最好做到的,不然OOM來襲我們不能徹底恢復。

1。防止OOM恢復過程中的crash

假設一個類有如下初始化和清除代碼:

void CMyClass::Init()
{
  m_pPointer = new CMyOtherClass;
}

void CMyClass::Destroy()
{
  delete m_pPointer;
}

如果new CMyOtherClass的過程中,內存耗盡,這個時候系統會直接跳轉到異常處理代碼,一般來說異常處理代碼會清除掉當前所有context,重新來過。這個時候會調用Destroy()。這個時候m_pPointer是沒有被賦值的。如果你沒有正確的初始化的話,delete m_pPointer就會造成問題。

因此,正確的做法應該是這樣:

void CMyClass::Init()
{
  m_pPointer = NULL;
  m_pPointer = new CMyOtherClass;
}

void CMyClass::Destroy()
{
  if (m_pPointer) delete m_pPointer;
}

當然,初始化也可以在c*****tructor裏面做。

這個故事告訴我們,在desktop裏面看起來鐵定會被執行的東西,在嵌入世界裏可能會跑得沒影。你要考慮到一個new,一個alloc,一個調用了這些東西的函數等,都有可能回不來。因此,在你準備隨時“就義”之前,請安排好“後事”。

其實每個變量要初始化,這是常識。但是有的時候,看起來沒問題的偷懶,就有可能引起嚴重問題。

2。防止內存孤兒的產生

另外一種情況,不是“秒殺”你的應用,而是會慢慢的讓你的應用癱瘓掉,這就是內存泄漏。內存泄漏的一個原因是你忘了在合適的時候去清除你申請的內存了,這怪你自己太粗心。不過有的時候,可能由於你意想不到的原因,會導致“內存孤兒”的產生,也就是沒人管、管不到的內存,從而造成內存泄漏。

舉一個例子:

CMyClass::CMyClass()
{
  m_pPointer = NULL;
  m_pPointer = new  CMyOtherClass;
}

CMyClass::~CMyClass()
{
  if (m_pPointer) delete m_pPointer;
}

請注意我們已經吸取了上面講的問題的教訓,正確的初始化了,也能正確的清除。但是,以下的代碼:

CMyClass* p = new  CMyClass;
...

如果new  CMyClass成功,但是在構建CMyClass的時候,new  CMyOtherClass失敗,會怎樣呢?新創建的CMyClass對象裏面的m_pPointer會保持爲NULL,這個沒問題,但是,CMyClass對象的指針,放到哪裏去了呢?

答案是哪裏也沒有放,因爲還沒來得及賦值給p,程序執行就走了,離開了,不回來了。你製造了一個孤兒。這片內存(裏面放着一個構建失敗的CMyClass),永遠沒有機會被釋放了,除非整個內存管理器被清除。

要怎麼解決呢?方法就是兩步構建。第一步,構建對象本身,第二步,構建對象內容。

改成這個樣子:

CMyClass::CMyClass()
{
  m_pPointer = NULL;
}

void CMyClass::Init()
{
  m_pPointer = new CMyOtherClass;
}

調用的時候:

CMyClass* p = new  CMyClass;
p->Init();
...

這樣,無論Init()是否成功,p裏面都放了CMyClass的指針。

其實我舉的例子還是有問題的:如果p->Init()不成功,那麼程序走了,臨時變量p也會不見掉。正確的做法應該是將指針放到一個外部可以隨時存取的context的成員中:

pContext->m_pPointer = new  CMyClass;
pContext->m_pPointer->Init();
...

以上講的兩件事情,都不是什麼大事,但是細節不注意,會給你們的代碼帶來大問題。請大家注意養成良好的設計和編碼習慣,稍微注意一下,我們一定能渡過內存危機!


上面的這兩種思想在iphone sdk中有了很好的體現, 特別是第二件事, 
Object *obj = [[Object alloc] init]; //這個其實這個就是一個兩步構件的思想。 

在iphone開發過程中使用了C++代碼的兄弟們就更應該注意這個安全隱患。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章