C++ 不是号称不限制你的开发方式么,每个库想怎么搞就怎么搞,这明明就是 C++的优势,不知道大家抱怨个啥?哈哈
接着说 std::string 的性能问题,举个具体例子吧,之前接手过一个项目,别的部门同事自己撸的一套 DirectUI 系统,用 tinyxml 解析界面节点,项目简单的时候没啥,随着ui越来越复杂,数千个节点,每个xml节点若干属性,每个属性就是一个字符串,我记得好像有500+ KB的 xml要解析,而且这部分界面还没法延迟初始化,必须启动加载时做完,启动十分慢。profile下来,很多时间卡在 tinyxml上,整个过程接近 3秒,费时最前的操作卡在处理各种字符串的操作上。
把 tinyxml 换成其他 xml库 ?没那么容易,项目各处模块都在依赖 tinyxml的各种接口和类。一开始觉得内部的 TiXmlString 实现有问题,换成 std::string,vc 2012下时间从3秒增加到4秒,更不靠谱(vs2012应该已经有所谓SSO了),所以人家 tinyxml 这里用自己的 TiXmlString 肯定也是比较过的,不然干嘛不用 std::string 。
但问题总得解决,所以还得优化字符串实现:
-
自己重新给 TiXmlString 实现了一套新的 SSO ,因为 xml里面很多小字符串,10个字节以内的占比很多,这部分用 TiXmlString 里面一块静态空间存储,随着capacity变化,超过限制长度的字符串才会开辟新的空间存储,这样避免了大量的内存分配,和碎片,总解析时间从3秒下降到 2秒。
-
还是嫌慢,又把 tinyxml 继续改写,增加把文本 xml编译成二进制格式的功能,平时开发用xml,实际发布用二进制版本的 xml,免去整个文本解析过程,时间进一步从2秒缩短到 0.8 秒。
-
还嫌不够快,接着改进二进制 xml文件结构,扫描整个 xml里面用到的所有字符串,统一做一个字符串常量表放在文件最前面,这样,二进制 xml文件里涉及到字符串的地方从缘来一段内存变成字符串表的一个索引 int,整个 TiXmlString 也变成对字符串常量表里某个索引的引用,这样彻底避免了字符串分配和维护操作,而且总内存变小了,比如 “type”, “button”, “label” “text” 等高频字符串只存储一遍,以前 1000个 “text” 字符串要解析1000遍,还要创建分配 1000次内存,有了常量表以后,所有的 “text” 都是一个引用,不需要1000便解析,更不需要1000次构造,时间从 0.8秒继续下降到 0.2秒。
运营常识,客户端项目,启动时间直接和用户流失率成正比,tinyxml字符串优化,前后把优化前的 3秒下降到优化后的 0.2秒,基本xml解析不再是一个瓶颈。
为什么不同的库要实现不同的字符串呢?从这个小例子可见一斑。
后来呢?嗯,后来有一天我不能忍了,我把整个项目的 gui系统弄成 Qt 的了,ui描述文件直接编译成代码,再也不用烦这些事情。
在结合看高票说的 QString,可以感受下。
所以大家才会说:人在做,天在看,信 Qt,保平安。。。。。