我收到Ken一封Email,这位仁兄浏览了我博客的中有关OpenAL的文章,遇到一些问题请求我的帮助。他在加载缓存后重复使用时遇到了一些OpenAL神秘的错误。

 

所以我阅读了他寄给我的代码片段,我注意到:

 

1
2
3
// use the static buffer data API

alBufferDataStaticProc(buffer, format, data, size, freq);

 

啊哈! 这可能就是你问题的根源!除非你真正需要,alBufferDataStatic应该完全被避免。你怎样才知道你需要使用它?有一条金桂玉律:如果你不知道这个问题的答案,那么你就不需要它。

 


(我不希望看上去对Ken太过严苛,这个问题很普遍,所以我决定写这篇文章(类似于我呼吁绝不要使用随Apple发布的示例代码一样))

 

那我为什么会认为要避免使用它?我相信你一定听说过要获得更好的性能,你应该使用alBufferDataStatic(),对吗?不!

 

那好,alBufferDataStatic()是什么?alBufferDataStatic将所有缓存数据的内存管理责任完全推给了你的代码。

 

我重复一遍:当使用alBufferDataStatic()时,应该对所有内存管理负责。

 

这就是所谓的性能提升。

 

等等!真的吗?这就是alBufferDataStatic的所作所为吗?

 

是的。

 

iPhone是共享内存空间的,它处理内存的方式以及当你的程序使用过多的内存时而被抛弃的方式是十分特殊的。它要求你密切注意及处理你使用的内存。那意味着如果你希望使你的第一人称射击游戏可以稳定地保持在30FPS,你必须从iPhone榨取最后一个字节内存,因此你可能需要花费几个星期来调整你的声音代码使得你可以随时密切控制内存使用情况。

 

对于其他 %99.9999可能需要使用OpenAL的程序(即使你使用了大量的音效),使用alBufferDataStatic()只不过是给你带来额外的麻烦而已。这里有另一条规则:如果你不打算专门雇佣一个全职开发者处理音效代码,那么你不需要使用alBufferDataStatic()。

 

快速阅读一下有关alBufferDataStatic()的技术文档。

 

这是什么意思?

 

意思是: 当你使用alBufferData()时,你将加载声音数据到局部缓存(你使用malloc建立的缓存),当你调用alBufferData()时, OpenAL 将复制所有字节到它自己的缓存区。然后,你要释放局部缓存,OpenGL现在拥有自己的缓存。其缺点是:在很短的一段时间内,你将拥有两份声音数据在内存中。优点是:内存管理非常非常容易。

 

如果你的程序在缓存复制时崩溃,那么你可能需要alBufferDataStatic()。但是更有可能的是你的内存管理机制在什么地方十分糟糕。(另外需要注意如果你加载一个很大的声音数据到内存中,那么我可以告诉你,这是错误的,你应该采用数据流来加载数据)。

 

好了,你已经绝对地肯定你要管理你自己的声音内存?可能需要使用alBufferDataStatic(),但是首先:这里有另一条金桂玉律:如果你正在读我这篇文章来决定是否使用它;那么不要使用。赶快找到这条代码,赶快删除它。直接删除。

 

很明显,我在用一种夸张的方式试图说明我的观点。我不知道你的代码,但这里有一些我在我的代码中经常出现的bug:

 

忘记释放对象导致内存泄漏,最终导致程序崩溃。

 

不小心释放了一个自动释放对象,引起崩溃。

 

不小心释放了一个从属于其他对象的对象,使程序随后(很久很久以后)崩溃。

 

malloc了一些内存,忘记free,引起泄漏,最终崩溃。

 

free了一些 malloc的内存,然后试图再使用,引起程序完全疯狂。

 

这个列表还可以继续。但是你看到一个共同点没有?内存。为什么我在不必要的情况下还要承担更多内存管理的责任?为什么开发者还要一如既往地使他们的生活变得更糟糕?

 

这里有些陈词滥调:

 

更少的代码 == 更少的bug  更多的代码== 更多的bug。 因此代码越少越好。

 

不要添加你现在不需要的代码。(这很常见,你可能会想:我可能以后做X时会需要一个方法,所以我现在就写出来,不必等到用时在写。)错!“未来”当你需要时,你需要的是Y,而不是X,你还是需要重写。或者更有可能是你永远也不需要用到X,你只是浪费了时间在不必要的代码上。

 

不要过早地进行优化。使代码可以工作为先。然后再找到你需要优化的地方。如果试图过早优化,那么最终的结果是你花费了所有的时间在使一个方法十分伟大(直到后来才知道此方法仅仅几秒钟才被调用一次,所以这是一段最缺乏效率的代码而且没有人会注意到它。)

 

所以,使用alBufferDataStatic()将打破我可爱的全部三条陈词滥调。

 

不要这样做。

 

你只会让你自己图添悲伤而且你的代码会问题多多。请使用alBufferData()。它可以工作。它很容易。资深的使用OpenAL的工程师保证使用alBufferData()没有内存问题。如果你打算移植你的代码,alBufferData()还是可以工作!alBufferData() 使你呼吸更新鲜!

 

我已经在6个程序中使用了OpenAL代码。一些是游戏,一些是实用程序。一个没有使用alBufferDataStatic()的“音板”式程序同时播放32个声音(这是目前允许的最大数目,可能以后仍然是),它能够处理庞大的声音文件(通过数据流)。是不是这个超级疯狂代码实现的超难任务可以算是一种技能?

 

不。恰恰相反。我尽量使我的程序保存简单。

 

保持代码简单,不要使用不需要的东西。

 

原文见:alBufferDataStatic: why you should avoid it