Qt 当动态创建的对象具有父对象时,QML不会释放大量内存
我使用Qt 当动态创建的对象具有父对象时,QML不会释放大量内存,qt,memory-management,qml,Qt,Memory Management,Qml,我使用Component.createObject()方法动态创建对象。之后,我使用destroy()方法删除对象。 如果调用方法Component.createObject(null)时没有父参数(带null),则destroy()方法会释放内存。如果我使用一些父对象调用该方法,则destroy()方法不会释放大量内存。创建大量对象时,这会导致Windows操作系统中每个进程的内存超过允许的数量,并导致应用程序崩溃。 重现问题的代码: main.qml import QtQuick 2.8
Component.createObject()
方法动态创建对象。之后,我使用destroy()
方法删除对象。如果调用方法
Component.createObject(null)
时没有父参数(带null),则destroy()
方法会释放内存。如果我使用一些父对象调用该方法,则destroy()
方法不会释放大量内存。创建大量对象时,这会导致Windows操作系统中每个进程的内存超过允许的数量,并导致应用程序崩溃。
重现问题的代码:
main.qml
import QtQuick 2.8
Item {
visible: true
width: 640
height: 480
Scene {
id: scene
anchors.fill: parent
}
}
import QtQuick 2.8
Item {
id: scene
Component.onCompleted: {
var tileComponent = Qt.createComponent("Tile.qml");
for (var i = 0; i < 200000; ++i) {
var tile = tileComponent.createObject(scene);
// var tile = tileComponent.createObject(null); // this works well, but I need a parent
tile.destroy();
}
}
}
import QtQuick 2.8
Rectangle {
width: 100
height: 100
color: "orange"
}
Scene.qml
import QtQuick 2.8
Item {
visible: true
width: 640
height: 480
Scene {
id: scene
anchors.fill: parent
}
}
import QtQuick 2.8
Item {
id: scene
Component.onCompleted: {
var tileComponent = Qt.createComponent("Tile.qml");
for (var i = 0; i < 200000; ++i) {
var tile = tileComponent.createObject(scene);
// var tile = tileComponent.createObject(null); // this works well, but I need a parent
tile.destroy();
}
}
}
import QtQuick 2.8
Rectangle {
width: 100
height: 100
color: "orange"
}
带有父级的变量在destroy()
之后使用40 MB内存,而不带父级的变量使用12 MB内存。如果我继续创建和销毁这些对象,使用的内存将继续增长。
如何使用父对象动态创建和销毁大量对象,以避免内存问题?
我已经在Windows7x64上测试了Qt5.9.1(MingW5.3.0编译器)和Qt5.8.0(MSVC2015)。QML并不真正喜欢释放内存,但你也可以通过调用gc()
强制释放内存,按顺序调用它通常会有好处,即使在第三次调用之前,它也会不断压缩额外的内存
从正面来看,如果您创建更多对象而不是分配更多内存,那么使用的内存将被重用
总之,QML是一个内存猪。即使从QML创建简单的、不可见的QObject
s也有一个缺点。所以,我建议,如果可能的话,使用一些C++驱动的模型,而不是成千上万的QML对象只是坐在内存中,延迟加载,按需加载-这样的技术将为您的内存使用奇迹。 < P>这种行为对于QT来说是正常的。你不需要对此做任何事情。如果您继续测试,您将在某个时候看到内存使用停止增长
我建议不要使用gc()
,因为它确实没有任何帮助。它强制Qt做一些它在需要时会自动做的事情
可以通过在JavaScript中调用gc()手动调用垃圾收集器。这将导致执行一个全面的收集周期,可能需要几百到1000毫秒才能完成,因此应尽可能避免
我只能猜测:parent
可能包含对某个包装器的引用,该包装器没有被删除。我尝试删除parent本身(动态创建场景,然后调用destroy()
),但没有帮助。似乎gc()
只会为没有父对象释放内存:。gc()
代表“垃圾收集”——它不涉及任何对象,它涉及不再被任何对象使用的内存。请记住,QML远非完美无缺,它实际上会删除仍在使用的对象,所以不要期待奇迹发生。我已经测试了大量具有父对象和数百兆ram的对象,我需要动态创建和删除很多对象,但同时在场景中只能有大约100个可见对象。因此,我只能创建一些对象池,然后我将更改未使用对象的属性,而不是创建/删除新对象。@BlackHoleTracer这个想法不好。您希望Qt会尽快释放所有未使用的内存,但Qt的方法有所不同。它只会在真正需要的时候释放内存。你不需要关心这个。每分钟创建和删除数千个对象,应用程序就会正常工作。答案可能取决于平台。在Android上,QML很容易耗尽内存。例如,在Android上播放的音频文件只保留在内存中,直到最终出现错误-19。所以,如果你的应用程序播放大量音频文件,你将不得不接管内存管理。我现在又测试了一次:当点击按键时,开始创建新的大部分对象。你完全正确!内存使用量在130 MB上停止增长。第一次,当我测试类似的情况时,我非常快地创建了新对象,所以没有足够的时间释放内存,应用程序崩溃。谢谢,菲利普!不要信任自动gc()
。当你看起来合适的时候,手动调用它,因为它有时真的很懒,可能会决定简单地崩溃你的应用程序比完成工作要省事。尤其是当您希望它自动delete()
删除那些没有引用的对象时。还有一个问题是在我的真实代码中。它与QML中的这种情况有关:var testObj={'a':10,'b':20,'c':60,'d':70};对于(testObj中的var key){delete testObj[key];}
此代码将仅删除2个元素,但不会删除所有元素。纯javascript将删除所有元素。