原文链接:http://www.cnblogs.com/zouzf/p/4216046.html
tinyxml优化之一说到了效率在差别有三方面的原因:解析的方式、内存分配(字符串操作)、冗余的安全性检查,那么优化就从这些方面着手:
1、修改解析的方式
无论是tinyxml1的逐字符扫描还是tinyxml2的递归解析,最本质的都是扫描每一个字符来进行分析,如果我们知道每一个节点、属性的name和value的长度和位置,在解析的时候按需要移动文本指针,岂不是可以快很多么?
实现思路如下:
(1)、把XML文件读进内存,然后用tinyxml(tinyxml1和tinyxml2都一样)自身的解析方式进行解析;
(2)、获取到解析好的XMLDocument,按照一定的规则把每个节点、每个属性的name和value保存到文本,还要把一些额外的信息如节点间的父子兄弟关系、节点有多少属性、每个节点每个属性的name和value的长度等信息也保存到文本里;
(3)、读取那个特殊格式的文本到内存,根据一定的规则构建出所有的节点,再根据保存进来的额外的信息给每一个节点补充上它的属性信息 以及 节点间的父子兄弟关系。在解析这个文本时,不需要逐字符解析,而是根据先读取到的那些额外的信息就可以得知某个节点有几个属性、每个属性的name和value有多长,这样子就可以让文本指针每次移动多少个字节了~~
2、内存分配(字符串操作)
tinyxml1:不使用STL的话,分配一块内存把XML文件的数据都拷贝过来,修改tinystr类,在解析的时候涉及到字符串操作时不进行内存分配和拷贝操作,而是把tinystr对象的char*直接指向大内存块的对应的位置;如果使用STL,这部分没有什么好修改的,毕竟,给STL::string赋值时,它都是自己管理内存的。
tinyxml2:本身它就会分配一块大内存把XML文本的数据拷贝过来的,解析的时候它自身也是把strpair类的char*直接指向大内存块的某个位置而不会重新分配内存,也没啥好做的。
3、冗余的安全检查
添加新的addElement、addAttribute方法,解析的时候每次添加节点、属性的时候,不检查是否已有同名的节点或者属性;这个检查交由XML文档的提供者来负责吧。其实,这个根本不需要担心,第一步的时候我们需要把用tinyxml自身的解析方法来解析 然后 在根据特定的规则把保存成特定格式的文本,在这一步的解析里,如果XML文本有啥问题也会被检查出来的,提前修正即可。
分析
上面三个步骤,其实第二步没啥用,因为我们项目用到的tinyxml1是使用了STL::string的。。。。剩下的第一步和第三步,明显可以看出第三步是比较简单的,90%的工作量和难度都是在第一步里,但是刚开始我只做了第一步而没有做第三步时,发现效率提高不了多少。。。配合上第三步才有60%~70%的提高,这让人很蛋疼,因为第一步实在是占了所有优化工作的90%以上,都想直接把第一步删掉只保留第三步了,但我没有测试过效果如何。。。。
后来进一步优化的时候发现,在第一步时,可以把那些额外的信息保存成连续的一块,再把所有有用的字符串保存成连续的一块,在解析完之后可以只保留字符串那一块而把额外信息那一块删掉(当然不是直接删掉,而是分配内存把字符串那一块的信息拷贝过来,在解析的时候移动指针时加上一个偏移量即可,解析完即可把带有额外信息和连续字符串那块内存释放掉了),这样子可以让内存比原来减少30%~40%,毕竟,XML文件里所有的双引号、空格、尖括号等没用的信息都被删掉了~~~额外的惊喜
其他方案
后来在和同事讨论的时候也想过一个方案:直接用pugixml来解析,然后再转成tinyxml树,毕竟,相对于tinyxml,pugixml的效果高得吓人(高20~30倍)!后来想了一下,我们第一步的工作可以通过tinyxml的更强一点的安全检查来检查出XML文件是否有些小瑕疵,然后还能减少内存,这都是挺重要的方面,另外,pugixml解析完转成tinyxml树,这一步的消耗估计也是挺大的,总的来说可能这种方案的效率不见得比上面的方案能提高多少(说不准还会低,毕竟,遍历pugixml树来构建tinyxml树。。。),就不考虑了。
终于,可以在不改变原来接口的基础上,使得XML文件解析的效率提高了60%~70%,占用的内存减少了30%~40%,真是莫大的惊喜,要知道,项目有不少XML文件都是上万行的,三万行的文件也有七八个,一个就有3M大~~~通过这个优化,也学到了不少东西~~也知道了自己非常大的一个弱点就是:看代码的能力比较差,有待提高。
代码,后面再贴出来吧,有需要的朋友可以留言。
原文链接:http://www.cnblogs.com/zouzf/p/4216046.html