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将删除所有元素。