Qml 中的那些坑(一)---Image 的内存
【写在前面】
首先,要提一个版本 bug。
因为一个类似的 bug 是在 Qt 5.13.0 中 ( 5.12 则没有),由 QQuickPaintedItem 引起的。
详见:[QTBUG-78063] QQuickPaintedItem directly used, will grow infinite memory - Qt Bug Tracker
同样的,使用 Image
后,也会无限增长内存。
但是先忽略这个bug,因为这里要讲的是 Image 的内存。
【正文开始】
在 qml 中,Image 作为最常用的控件之一,简单又方便。
然而,程序中大量使用 Image 后,我发现有些不对劲。
例如,我使用一张高清的大图作为背景(2000 x 2000 background.jpg):
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: root
visible: true
width: 1024
height: 680
Image {
anchors.fill: parent
source: "background.jpg"
}
}
因为是JPG,它的压缩率很高,因此只占用 400KB 的空间。
运行起来发现,内存占用 40MB (左右),看起来似乎可以接受。
然而,接着多添加几张图片试试:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: root
visible: true
width: 1024
height: 680
Image {
anchors.fill: parent
source: "background.jpg"
}
Image {
anchors.fill: parent
source: "background2.jpg"
}
Image {
anchors.fill: parent
source: "background3.jpg"
}
}
结果每多一张就增加 20MB,现在占用 80MB 内存了!
这已经完全不能接受了好吗,虽然不可能每张图片都是 2000 x 2000,但也架不住图片多啊(ಥ _ ಥ)。
于是我开始在文档中寻找答案 > > >
最终,我找到了,那就是 sourceSize: size
此属性保存已加载图像的实际宽度和高度。
与缩放图像绘制的宽度和高度属性不同,此属性设置为加载的图像存储的实际像素数,以便大图像不会占用超过必要的内存。
也就是说,该属性可以限制实际内存中图像的的大小。
现在来试一下效果:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: root
visible: true
width: 1024
height: 680
Image {
anchors.fill: parent
source: "background.jpg"
sourceSize: Qt.size(1024, 680)
}
}
现在内存降到了 20MB。
这样做的优点显而易见,那么缺点就是:
在窗口 <= size(1024, 680)
(初始大小)的时候,不会有任何区别,而在 > size(1024, 680)
时,会变模糊。
具体原因是:放大失真后进行了平滑处理 ( 来源于 smooth
属性,默认 true
,因此设为 false 将会出现明显锯齿 )。
因此,我的建议是:将 sourceSize
设为一个合理的大小(并且最好稍微大一点)。
【结语】
最后,讲一些题外话:
Image
有一个属性 cache
:
Specifies whether the image should be cached. The default value is true.
Setting cache to false is useful when dealing with large images, to make sure that they aren't cached at the expense of small 'ui element' images.
翻译:
指定是否应缓存图像。 默认值是true。
在处理大图像时,将缓存设置为false非常有用,以确保它们不会以小的“ui元素”图像为代价进行缓存。
开启 cache
后,在 Qml 内部, 会维护一个 QHash
。
也就是说,同样 Image 只会加载一次,这样做明显是有好处的,那么文档中所说的,大图像设置为 false 的好处又是什么呢,是大图像不会被多次使用而省去了缓存的工作吗?
这点暂时还在摸索中...