可爱的小奶牛
呵呵,标题党,标题党。本文其实想进行严肃的技术分享的,那就是研究下在QT库中占有重要地位的Copy-On-Write Data Share技,所以就是QT's Copy-On-Write = Cute COW:ppb_50Copy-On-Write 写时复制,是一项非常重要并被广泛应用的空间优化技术。最近几年,着个小奶牛在文件系统(ZFS, BtrFS, Ext3,Ext4等),虚拟机(比如Vmware的虚拟机快照功能)中被疯狂地使用。但是在一般的软件开发中,对内存的优化使用方面,往往忽略了对着头小奶牛的关注。但在QT库中,写时复制技术却遍布整个QT库的代码中,在QT的技术术语中,小奶牛有另一个名字,叫Implicit Sharing。这项技术,可以消除哪些不需要的数据复制,特别是在大量使用字符串和图片等绝大多数情况下都是只读的场合。
QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1; // p1 and p2 share data
QPainter paint;
paint.begin(&p2); // cuts p2 loose from p1
paint.drawText(0,50, "Hi");
paint.end();
上面的代码显示了隐式共享是如何工作的,对于2个QPixmap图片对象p1,p2.p2 = p1这个操作,将不产生任何新内存占用,在内部,p1,p2所指向的图片数据是同一片内存。 但是一旦用了QPainter对其中一个对象发生了写操作。这个隐式共享的机制将立即感知到应该把图片的内存复制一份新的了,否则原意是只修改p2, 但p1也会被修改了。这个过程,在QT中叫detach。经过了detach,p1,p2就指向2个不同的独立的内存区域了,paint.end()语句后,p1将保持原状,而p2会如期望的那样被画上了一个"Hi“。
在QT库中,几乎所有能使用这项技术的场合都毫不犹豫得使用了。
实现这一切效果的,大部分都是2个类的功劳: QSharedData 和 QSharedDataPointer。
QSharedData类是个很简单的实现了引用计数的基础类, 所有希望能使用隐式共享的类都必须从QSharedData继承,并有QSharedDataPointer来使用。下面是QT文档中使用隐式共享的一个例子:
#include
#include
class EmployeeData : public QSharedData
{
public:
EmployeeData() : id(-1) { name.clear(); }
EmployeeData(const EmployeeData &other)
: QSharedData(other), id(other.id), name(other.name) { }
~EmployeeData() { }
int id;
QString name;
};
class Employee
{
public:
Employee() { d = new EmployeeData; }
Employee(int id, QString name) {
d = new EmployeeData;
setId(id);
setName(name);
}
Employee(const Employee &other)
: d (other.d)
{
}
void setId(int id) { d->id = id; }
void setName(QString name) { d->name = name; }
int id() const { return d->id; }
QString name() const { return d->name; }
private:
QSharedDataPointer d;
}; 歪楼党 :mk_52
http://www.myjgd.com/jgdi/Holidays_ChristmasCow-lilanimalshop-1822491.gif
页:
[1]