iphone 如何渡过内存危机(OOM)

来源:互联网 发布:windows安装git服务器 编辑:程序博客网 时间:2024/04/27 23:23
讲两件事情:第一件是我们必须做到的,不然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;}

当然,初始化也可以在constructor里面做。

这个故事告诉我们,在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++代码的兄弟们就更应该注意这个安全隐患。
原创粉丝点击