Qt6之字符串类内存分配新变化——16的次方增加

qt提供了比标准c++ string更强大,更丰富,更实用的字符串类QString,它的主要功能22个已经在之前逐一分析过,感兴趣的可前往以下链接查看,本文主要重点分析下qt在字符串类上面做的优化,主要是两个方面,隐式共享内存分配策略

9-Qt6 QString和QChar_qchar qstring_闫有尽意无琼的博客-CSDN博客https://yanchenyu.blog.csdn.net/article/details/119640571 也可关注官方文档:

QString Class | Qt Core 6.5.0https://doc.qt.io/qt-6/qstring.html#details

一、隐式共享

共享类由一个共享数据块及指向这个块的计数器组成,当共享对象被创建,这个块的计数器的值会被设置为1,并且当有新的对象指向共享数据库,那么他的计数器就会+1,当对象不指向这个内存块时,计数器会减少,当计数器为0时,这个共享块将会被删除。

简单的说,当两个对象共享同一份数据时,如果数据不改变则不进行数据的复制(仅浅拷贝),而当数据改变时则进行数据复制即进行深拷贝。

浅拷贝,只做两件事情,设置一个指向共享数据块的指针,再修改引用计数的值;

深拷贝,生成一个对象的完整复制品;

显然深拷贝对资源的占用比如cpu、内存等将需要花费更多的资源,而浅拷贝仅仅是指针引用和计数,效率会非常高。

Qt的隐式共享技术,就是把浅拷贝和深度拷贝结合起来,以提高运行效率的同时还是资源占用降低。以下代码解释:

QString str1="china";
    qDebug()<<"&str1="<<str1.data_ptr();
    QString str2=str1;
    qDebug()<<"&str2="<<str2.data_ptr();
    str2.at(0);
    qDebug()<<"&str2.at(0)="<<str2.data_ptr();
    str2[0]='a';
    qDebug()<<"&str2="<<str2.data_ptr();
    qDebug()<<"&str1="<<str1.data_ptr();

 当第一次str2=str1,可以看到地址并未变化,说明仅发生了浅拷贝,它们指向同一个内容。

紧接着我们调用at去访问str2首元素后,地址仍未变化;

最后修改str2的第一个元素后,str2地址发生变化,因为已经进行了深拷贝,,也就是说它指向的数据结构已经是新的区域,指针地址也随之发生变化,即新的地址新的值,但str1此时地址仍未变化即最初的地址,也是最初的值。

以上,充分说明了,qt是深拷贝和浅拷贝进行结合使用,以最大化的减少资源占用,就是这一点一滴不知不觉的优化,积累起来提高效率。

二、内存分配策略

容器类 |Qt核心6.5.0https://doc.qt.io/qt-6/containers.html

 那我也用代码展示了,内存分配情况的确是文档中描述的,可以是8,24,56,120……;

 //上面qt6官方文档是如上面描述:

通过实验可以得出结论,qt6在内存方面发生了新变化,确实内存在以16的次方在增加,而不是再是所谓的qt5中众说纷纭的三种情况分配了。(截止23年5月号称所谓的qt6的新书还在继续宣扬下面的3种分配方式)。

而qt5时描述说分为3种情况:

  • QString每次分配4个字符,直到大小达到20个字符;
  • 当大小在20到4084个字符之间,每次分配内存块为当前空间大小(即为当前的2倍的速度增长)。准确地说,是分配下一个2的整数幂减12(即2^n-12)。这是因为在某些内存分配器中,会预分配几个字节的空间用于簿记内存开销(实现内存分配的时候会使用Bookkeeping,深入了解可前往内存管理内幕中查看“其它malloc实现”),因此分配大小为2的整数幂时性能较低。
  • 从4084字符开始,每次分配2048个字符(4096字节,即4KB,刚好等于一个32位逻辑地址空间计算机系统的页的大小),原因是现代操作系统重新分配一个缓冲区时不会将整个数据全部复制(隐式共享),物理页只进行简单地重新排序,实际上只需要复制首页和尾页的数据。

 总之无论qt采用过去的3种分配方式,还是现在16次方的分配方式,qt都是利用隐式共享和动态的内存分配策略,优化资源占用,提高效率。

猜你喜欢

转载自blog.csdn.net/yanchenyu365/article/details/130705041