Linux系统编程之C 游戏程序优化(5)
文章作者 100test 发表时间 2007:03:14 16:39:25
来源 100Test.Com百考试题网
这还不是STL内存使用的全部。一定要了解当你使用clear方法时,容器是否真的释放掉了它的内存。如果没有,就可能产生内存碎片。比如,如果你开始游戏的时候建立了一个空的vector,在游戏过程中增加元素,然后在游戏restart时调用clear,这时vector未必释放它的全部内存。这个空的vector,可能依然占据了堆中的内存,并使其变成碎片。如果你真的需要这样来实现游戏的话,对这个问题有两种解法。一是你可以在创建vector时调用reserve(),为你可能需要的最大数量的元素保留足够的空间。如果这不可行的话,你可以强迫vector完全释放内存:
Vector V.
// … elements are inserted into V here
Vector().swap(v). // causes v to free its memory |
Set、list以及map都没有这个问题,这是因为他们为每个元素分别分配和释放内存。
6、高级特性
编程语言的某些特性你可能没必要用到。看上去简单的特性可能会导致低下的效率。而看起来复杂的特性没准执行得很好。C 的这些黑暗角落异常依赖于编译器。当你要使用它们时,必须了解它们的代价。
C 的string就是一个看起来不错的例子,但是在效率极其重要的场合应该避免使用,考虑下面的代码。
Void Function(const std::string &.str)
{
}
Function("hello"). |
对Function()的调用包括了对给定const char*参数的构造函数的调用。在普遍的实现中,这个构造函数执行了一个malloc(),一个strlen(),以及一个memcpy(),而析构函数立刻上来做了一些无意义的事情。(由于该例子中的string没有被更多的应用)然后又跟了一个free()。这里的内存分配完全是浪费,因为字符串“hello”早就在程序的数据段中了。我们早就有它在内存中的副本了。如果Function定义了一个const char*的参数,那么完全没有了上面所说的那些额外的调用。这就是为了使用方便的string而付出的高昂代价。
模板是效率的对立面的一个例子,根据语言标准,编译器在模板实例化为一个具体的类型时产生代码。理论上,看上去是声明了一个模板,但却实际产生了大量的相似的代码。如果你有了class1的指针的vector,也有class2的指针的vector,你就在你的可执行文件中做了两份的vector的拷贝。
事实上,大多数的编译器做得更好,首先,只有实际被使用到的模板成员函数被产生代码。其次,如果事先了解了正确的行为,编译器可以只产生一份代码的拷贝。你可以从vector的例子发现这一点,确实只产生了一份代码(一般是vector )。有了好的编译器,模板还是可以在保持高效的同时提供你一般编程的好处。
C 的一些特性,比如初始化列表以及前自增,一般来说可以提高效率。而象其它的一些特性比如运算符重载以及RTTI则看起来似乎是清白的,但却有时带来严重的效率问题。STL的容器则描述了盲目相信函数的算法运行时间可以如何让你误入歧途。避免使用潜在的低效率的语言或类库特性,同时花些时间来了解你的编译器的各种选项。你会很快的学会设计高效的代码,并且解决掉你的游戏中的效率问题。
7、其他参考
Thanks to Pete Isensee and Christopher Kirmse revIEwing this gem. Cormen, Thomas, Charles Leiserson, and Ronald Rivest, Introduction to Algorithms, Cambridge, Massachusetts, MIT Press, 1990
Isensee, Peter, C Optimization Strategies and Techniques, www.tantalon.com/pete/cppopt/main.htm Koenig, Andrew "Pre-or Postfix Increment"
The C Report, June,1999 Meyers, Scott, Effective C , Second Edition, Reading, Massachusetts: Addison-Wesley Publishing Co., 1998.
Sutter, Herb, Guru of the Week #54: Using Vector and Deque, www.gotw.ca/gotw/054.htm