Qt学习06——内存分配策略

QString中的内存分配策略

QString在一个连续的内存块中保存字符串数据,当字符串长度不断增长时,QString需要重新分配内存空间,QString使用的内存分配策略如下:

1. size <= 20, 每次以4个字符空间(8字节,即1B)的步进增长;

2. size > 20 && size < 4084,内存块以2倍速度增长;

3. size >= 4084,每次以2048个字符空间(4096字节,即4KB)的步进增长;

QString test(){
    QString str;
    for(int i=0;i<9000;++i)
        str.append("a");
    return str;
}
这里定义了一个QString对象str,然后为它追加9000个字符。根据QString的内存分配策略,该循环将进行14次内存分配:

4、8、16、20、52、116、244、500、1012、2036、4084、6132、8180、10228。最后一次内存重新分配之后,QString对象str具有一个10228个Unicode字符大小的内存块(20456字节),其中有9000个字符空间(18000字节)被使用。


来源:陆文周《Qt5 开发及实例(第2版)》

//===============================================分割线=========================================================//

分配策略第二点说的不够准确,这里补充一下,其中涉及一些内存管理相关知识已附上链接。

关于QString的内存分配策略,在官方文档中是这样写的:

Consider the following code, which builds a QString from another QString:

QString onlyLetters(const QString &in)
{
    QString out;
    for (int j = 0; j < in.size(); ++j) {
        if (in[j].isLetter())
            out += in[j];
    }
    return out;
}

We build the string out dynamically by appending one character to it at a time. Let's assume that we append 15000 characters to the QString string. Then the following 18 reallocations (out of a possible 15000) occur when QString runs out of space: 4, 8, 12, 16, 20, 52, 116, 244, 500, 1012, 2036, 4084, 6132, 8180, 10228, 12276, 14324, 16372. At the end, the QString has 16372 Unicode characters allocated, 15000 of which are occupied.

The values above may seem a bit strange, but here are the guiding principles:

  • QString allocates 4 characters at a time until it reaches size 20.
  • From 20 to 4084, it advances by doubling the size each time. More precisely, it advances to the next power of two, minus 12. (Some memory allocators perform worst when requested exact powers of two, because they use a few bytes per block for book-keeping.)
  • From 4084 on, it advances by blocks of 2048 characters (4096 bytes). This makes sense because modern operating systems don't copy the entire data when reallocating a buffer; the physical memory pages are simply reordered, and only the data on the first and last pages actually needs to be copied.
重要的是分配策略那三点,我解释一下:
  • QString每次分配4个字符,直到大小达到20个字符;
  • 当大小在20到4084个字符之间,每次分配内存块为当前空间大小(即为当前的2倍)。准确地说,是分配下一个2的整数幂减12(即2^n-12)。这是因为在某些内存分配器中,会预分配几个字节的空间用于簿记内存开销(实现内存分配的时候会使用Bookkeeping,深入了解可前往内存管理内幕中查看“其它malloc实现”),因此分配大小为2的整数幂时性能较低。
  • 从4084字符开始,每次分配2048个字符(4096字节,即4KB,刚好等于一个32位逻辑地址空间计算机系统的页的大小),原因是现代操作系统重新分配一个缓冲区时不会将整个数据全部复制(隐式共享),物理页只进行简单地重新排序,实际上只需要复制首页和尾页的数据。
此外,QByteArray和QList也使用类似的算法。

用一个实例测试一下
QString textediter::test(){
    QString str;
    for(int i=0;i<9000;i++)
    {
        str.append("a");
        ui->textEdit->append(QString::number(i,10)+"  "+
                             QString::number(str.size(),10)+"  "+
                             QString::number(str.capacity(),10));
//        ui->textEdit->append(QString::number(sizeof(str),10));
//        ui->textEdit->append(QString::number(str.size(),10));
//        ui->textEdit->append(QString::number(str.capacity(),10));
    }
    return str;
}
由于不同位数的系统内存分配有所差异,我分别在32位和64位环境下编译运行:
Qt5.4.0+MGW491_32+Qt Creator3.3.0
Qt5.8.0+MSVC2015_64+Qt Creator4.2.1
得到不同结果(左边32位,右边64位):
   
这里的capacity,文档说明是:
Returns the maximum number of characters that can be stored in the string without forcing a reallocation.
意思是:在不经过强制重新分配时,返回字符串所能存储的最大字符空间。
这里经过11次内存分配,在capacity达到20之后,每次增量均为2的下一个整数幂。

因此这里有2个疑问:
1、capacity的增量是否是内存增量?
2、在32位环境下,sizeof(str) = 4;在64位环境下,sizeof(str) = 8。同时capacity在20之前的增量相差了4字符。这之间的联系是什么?

希望有机会找到答案。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值