delphi中字符串于内存的问题
最近写了一个程序,发现运行时页面错误增量不停以2000/s的速度增加。通过不断注释,调试,最终定位问题出在在拼接sql语句中。
由于程序需要更新数据库,为了提高执行sql的效率,将多条sql拼在一起,一次刷新数据库。使用了sql=sql+str1的模式进行拼接。
实验一:
var str1, str2, str3: string; begin str1 := 'delphi '; str2 := 'oracle'; ShowMessage('str3='+IntToStr(Integer(str3))); str3 := str2+str1 ShowMessage('str3='+IntToStr(Integer(str3))); str3 := str3+str1; ShowMessage('str3='+IntToStr(Integer(str3))); end;
通过比较str3赋值前后指向堆的地址,发现str3前后的地址不一样,可以知道delphi中的string间加号操作符会内部申请一片空间,然后将右边的字符串拷贝过去。 而如果 只是str3:=str1;我们会发现str3指向的地址通str1指向的地址一样,其实只是增加了str1指向字符串的引用,当str1[1]:=#65;这时,str1指向的地址将会发生改变,str3指向的地址改变,这就是的delphi的 copy-on-write机制。 下面我们再来看第二个实验。
实验二:
var str4:string; begin while True do begin GetMem(str4, 1024*1024 ); FreeMem(str4) end; end;
这时我们去观察windows任务管理其中的页面错误那一选项,我们会发现,页面的错误量会剧增。
把1024*1024换成小一点,1024*10,这是我们会发现页面错误数增长的慢一些。继续减小,当减小为1024*4时,我们发现,页面错误没有增长了。
我们可以得出结论,当申请大于页面的内存时(猜测),会产生页面错误。
所以程序中出现大量页面错误,是因为拼接的sql语句过长,超过十几K,而且有大量拼接,导致程序不断的申请内存进行字符串拷贝,最终导致页面错误暴涨。
对于分配大内存会产生页面错误的原因还未弄清楚,先附上一图: