这个问题隐藏的很深,一般不容易察觉它造成的问题,而只是享受它提供的好处(节省内存,而且速度更快)。

但我发现它现在至少造成两个问题:

1. 把大量的QString放到QMap里,使用完毕后清空QMap,然而因为隐式共享的原因,实际上QString占用的大量内存得不到释放。这样程序积累了大量无用数据的内存,从此程序运行变得异常缓慢。

2. QFileInfo也有隐式共享问题,造成读取新文件信息的时候,估计要和旧文件信息全部对比一遍(就算是通过hash对比也很慢啊,我这里测试文件有11万个呢),确定没有这个新文件,然后才开始真正工作。这样效率极低。部分解决办法是使用const解决QFileInfo的问题。但是QString却不能使用const,因为我中间还要修改它。

只能慢慢研究了~

官方文档:

http://doc.qt.io/qt-4.8/implicit-sharing.html

http://doc.qt.io/qt-5/qstring.html

中文博客:

http://blog.csdn.net/yestda/article/details/17893221

http://blog.chinaunix.net/uid-27177626-id-3949985.html

http://blog.csdn.net/zhu_xz/article/details/6061201

------------------------------------------------------------------

隐式共享
说明对象在自操作前,指向一块共享的内存。
在自操作时,就会发生写时拷贝,让自己指向一块新的内存,这个内存也可以被其他对象引用,所以这个内存块有引用计数。当这块内存的引用计数为零时,会被回收。

所以,除非
QString *newString = new QString(theOldQString);
// then i forget to delete the newString
就会发生共享内存被引用但是却没被释放的问题。
其实隐式共享的内存确定可以被释放,但还是应用程序却仍然占据了高内存
这个就是你想要搞明白的问题

但是

for (int i=0; i<5000000; i++) {
QString str = "b";
list << str;
}
就不存在隐式共享的问题,会把整个对象放在list里

--你先吧所有的函数参数修改为标准的const引用类型~
------------------------------------------------------------------

for (int i=0; i<5000000; i++) {
QString str = "aaaa";
list << str;
}

QString str = "aaaa";
for (int i=0; i<5000000; i++) {
list << str;
}
两段代码会使用完全不同的内存大小

------------------------------------------------------------------

for (int i=0; i<5000000; i++) {
QString str = "a";
list << str;
}

for (int i=0; i<5000000; i++) {
QString str = "aaaa";
list << str;
}
两段代码也会使用完全不同的内存大小,而且使用内存都特别大。

------------------------------------------------------------------

理论知识:

不同于 Java 风格遍历器,STL 风格遍历器直接指向元素本身。容器的begin()函数返回指向该容器第一个元素的遍历器;end()函数返回指向该容器最后一个元素之后的元素的遍历器。end()实际是一个非法位置,永远不可达。这是为跳出循环做的一个虚元素。如果集合是空的,begin()等于end(),我们就不能执行循环。
  由于有隐式数据共享(我们会在后面的章节介绍该部分内容),即使一个函数返回集合中元素的值也不会有很大的代价。Qt API 包含了很多以值的形式返回QList或QStringList的函数(例如QSplitter::sizes())。如果你希望使用 STL 风格的遍历器遍历这样的元素,应该使用容器的拷贝,例如:

1
2
3
4
5
6
7
8
9
10
11
// 正确的方式
const QList<QString> sizes = splitter->sizes();
QList<QString>::const_iterator i;
for (i = sizes.begin(); i != sizes.end(); ++i)
...
 
// 错误的方式
QList<QString>::const_iterator i;
for (i = splitter->sizes().begin();
i != splitter->sizes().end(); ++i)
...

  这个问题不存在于那些返回集合的 const 或非 const 引用的函数。隐式数据共享对 STL 风格遍历器造成的另外影响是,在容器上运行着非 const 遍历器的时候,不能对容器进行拷贝。Java 风格的遍历器没有这个问题。
  foreach关键字
  如果类型名中带有逗号,比如QPair<int, int="">,我们只能像上面一样,先创建一个对象,然后使用foreach关键字。如果没有逗号,则可以直接在foreach关键字中使用新的对象。
  Qt 会在foreach循环时自动拷贝容器。这意味着,如果在遍历时修改集合,对于正在进行的遍历是没有影响的。即使不修改容器,拷贝也是会发生的。但是由于存在隐式数据共享,这种拷贝还是非常迅速的。
  因为foreach创建了集合的拷贝,使用集合的非 const 引用也不能实际修改原始集合,所修改的只是这个拷贝。

参考:http://jukezhang.com/2014/11/23/learn-qt-eight/

参考:http://www.devbean.net/2013/01/qt-study-road-2-implicit-sharing/

http://www.devbean.net/2013/01/qt-study-road-2-iterator/

可恶的QT隐式共享的更多相关文章

  1. Qt隐式共享机制

    1.浅拷贝 浅拷贝-引用类型.浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同),对其中任何一个对象的改动都会影响另外一个对象. 2.深拷贝 而深拷贝-值类型.深拷贝是指源对象与 ...

  2. Qt隐式共享与显式共享

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Amnes1a/article/details/69945878Qt中的很多C++类都使用了隐式数据共 ...

  3. Qt——数据的隐式共享

    一.隐式共享类 在Qt中有很多隐式共享类( Implicitly Shared Classes ),什么是隐式共享呢,请参考官方文档的说明. 好吧,翻译一下—— 许多C++类隐式地共享数据,使得资源使 ...

  4. C++中的深拷贝和浅拷贝 QT中的深拷贝,浅拷贝和隐式共享

    下面是C++中定义的深,浅拷贝 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用.也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用.以下情况都会 ...

  5. 关于QT中的隐式共享

    网上关于隐式共享的解释很多,在此不再陈述.本文主要是记录一下自己学习隐式共享的坑点: 即:隐式共享只发生在非指针的情况下!!!! 如下代码: QImage image1; QImage image2; ...

  6. QVector 和vector的比较(QVector默认使用隐式共享,而且有更多的函数提供)

    QVector和vector的比较: Qvector默认使用隐式共享,可以用setSharable改变其隐式共享.使用non-const操作和函数将引起深拷贝.at()比operator[](),快, ...

  7. 01Qt中的隐式共享

    隐式共享 ​ 隐式共享又称为回写复制(copy on write).当两个对象共享同一分数据时(通过浅拷贝实现数据共享),如果数据不改变,则不进行数据的复制.而当某个对象需要需要改变数据时,则进行深拷 ...

  8. QT隐式数据共享

    QT中许多C++类使用了隐式数据共享,最小化资源拷贝.当作为参数传递时,实际只传递了指针,这是底层完成的,程序员无需担心,即使是在多线程中,从Qt4开始: 记住,尽量使用const迭代器,vector ...

  9. QPointer更安全,QScopedPointer自动出范围就删除,QSharedDataPointer帮助实现隐式共享

    http://blog.csdn.net/hai200501019/article/details/8474582http://blog.csdn.net/hai200501019/article/d ...

随机推荐

  1. [转]SharePoint 2010/2013 使用Javascript来判断权限的三种方法

    本文讲述SharePoint 2010/2013 使用Javascript来判断权限的三种方法的实现方式及其优缺点. 1. 根据用户所在的SharePoint组(比如用户在Leader 组才可以使用审 ...

  2. JavaScript平常会跳的坑系列(一)

    function Foo() { //定义foo函数 getName = function () { console.log('1');}; console.log(this); return thi ...

  3. IP-MAC绑定导致网络故障

    前段时间将一台服务器A的服务迁移至了另外一台服务器B,外网IP地址也顺带迁移过来了,结果网络出现了问题. 其中内网是畅通的,但是外网IP怎么都连不上另外一台路由C(B和C是在一个交换机下的,网段也相同 ...

  4. 10.10_魔兽账号,OSC代码托管演示,研究SQL别忘记了,git

    (1)juedui8456juedui456chixin0769魔兽世界账号112288 (2)EasyXls.开源中国推出 PaaS@OSC 代码演示和运行平台.git.oschina.coding ...

  5. autoplay media studio couldn't load

    AutoPlay Media Studio 7 (English version) is installed on target machine. Following error occurred w ...

  6. cocos2dx如何添加popScene的场景动画

    说明 我们很容易在pushScene中添加动画 Director::getInstance()->pushScene(TransitionSlideInB::create(SCENE_TIME, ...

  7. foreach的一点理解

    首先什么样的数据才能实现foreach 1 实现IEnumerable这个接口 2 有GetEnumerable()这个方法 然后为啥实现这个接口或者有这个方法就可以实现foreach遍历 首先我先用 ...

  8. MVC中Razor视图基本语法(1)

    Razor前面,必须要跟前面的有空隙,即空格(多谢一楼提醒,url里面确实不用空格,如果要在url里面只需要@(ViewBag.),加上括号就好了),之后的必须要连贯,否则加小括号 1,在页面中输出单 ...

  9. 使用PHP在共享内存中存储数据集

    我们可以使用共享内存作为一种独特的存储选项,提供快速读/写操作和进程互操作性等优势. 对于 Web 应用程序,这意味着: 缓存存储(数据库查询.Web 服务数据.外部数据) 会话存储 应用程序之间的数 ...

  10. oracle工具 sqlplus 用户管理

    可以通过system用户对普通用户解锁.alter user scott account unlock; 工具:1/ sqlplusw sqlplus 自带.调用oracle安装目录下bin目录下的e ...