2010年10月19日 星期二

使用 alloca 或 malloc?

偶爾我們需要使用 malloc 或 realloc 來配置固定大小的記憶體空間,
使用上使用了這類指令,都要配上等量的 free() 或 delete 來釋放記憶體,
以免造成 memory leak 的狀況,當然也可以使用免 free() 的 alloca 指令。

這陣子在做某些 code 的 refactoring 時,
將某個有使用到 alloca 片段抽出來寫成新的 function
結果程式竟然就這樣發生了不正確的結果,

假設原本的片段長醬子


int main()
{
  BYTE* pbtText = NULL;
  pbtText = (BYTE*)alloca(4096 + 1);
  ZeroMemory(pbtText, 4096 + 1);
  memcpy(pbtText, pbtSource, 4096);
  // 在main()中可正常使用pbtText
  DoAnything(pbtText);// 在main()中呼叫其他 function 也可正常使用
  return TRUE;
}


改過的片段


int main()
{
  BYTE* pbtText = NULL;
  GetText(&pbtText);
  // 在main()無法正常使用 pbtText
  return TRUE;
}

void GetText(BYTE** pbtText)
{
  *pbtText = (BYTE*)alloca(4096 + 1);
  ZeroMemory(*pbtText, 4096 + 1);
  memcpy(*pbtText, pbtSource, 4096);
}


查了資料後發現,原來 alloca 是有個小眉角的,
alloca 所 new 出來的空間只會存在於使用他的 function 內,
所以它不用配對 free() 來釋放記憶體,而上例 pbtText 雖然是在 main() 中宣告的,
但是卻是在 GetText 中做記憶體配置,導致 main() 無法使用配置出來的空間,
所以在同一個 function 內臨時要用到記憶體使用 alloca 是不錯的選擇,
要跨 function 時就請使用 malloc 或 new 嘍。

正確的 malloc 程式如下


int main()
{
  BYTE* pbtText = NULL;
  GetText(&pbtText);
  // 正確的使用 pbtText
  free(pbtText);
  return TRUE;
}

void GetText(BYTE** pbtText)
{
  *pbtText = (BYTE*)malloc(4096 + 1);
  ZeroMemory(*pbtText, 4096 + 1);
  memcpy(*pbtText, pbtSource, 4096);
}


另外,alloca 是直接在 static 上面配置記憶體,速度比 malloc 快上許多,
但這在程式要做跨平台時移植時可能會造成困擾,
並不是所有的 OS 都可以支援 alloca 這種指令的操作,
相較之下使用 malloc 再記得 free 會保守安全許多。

沒有留言:

張貼留言