c++ - 大网格上的QML内存使用情况

标签 c++ memory-management qml

我有一款扫雷游戏,是一种练习QML的方法。

我所面临的问题是取决于网格大小的,无法控制的内存使用量迅速增长(> 700 Mb)。
我将其调整为最大150 * 150(更大的网格会导致崩溃,因为它是win32)。

像这样构建网格(使用Expose 2D C++ Game Board to QML using QAbstractItemModel中的位)(图像用于显示“bomb.png”,即用于显示地雷数量的文本):

Flickable {
    id: flickable
    width: parent.width
    height: parent.height

    enabled: false
    Column {
        id: cols
        Repeater {
            id: colRepeater
            model: mapSize //defined by user
            Row {
                id: rows
                property int y_pos: index
                Repeater {
                    id: rowRepeater
                    model: mapSize
                    Tile{
                        id: tile
                        x_coord: index
                        y_coord: y_pos
                        ...
                    }
                }
            }
        }
    }

这是我的Tile对象:
Rectangle {
    id: root
    ...
    Rectangle {
        id: tileDecoration
        visible: false
        anchors.centerIn: parent
        opacity:0
        Image{
            id: tileImage
            anchors.fill: parent
            visible: false
            source: ""
        }
        Text{
            id: minesText
            anchors.centerIn: parent
        }
    }
}

编辑:我的问题是如何提高内存使用率?对于扫雷车,我没想到它需要那么多。我还打算在Android上对其进行测试,因此有限的内存使用是一回事。

最佳答案

在查看QtQuick和QML性能时,我的主要原则通常是做得尽可能少。不要创建您现在不需要向用户显示的项目和绑定(bind)。

我无法提供确切的数字(毕竟,实际上并没有一个数字-它取决于项目和硬件),但是我建议QtQuick最适合以个位数显示数千个项目中的数字。屏幕上的时间。不仅如此,资源使用和性能也会开始变得有些粗糙。

不论好坏,QML是一种非常容易表达的语言,它很容易隐藏成本。在其中工作时,您需要在编写此代码时考虑实际情况。您创建的每个Item都是分配的QQuickItem子类,而您设置的每个属性都是一个C++函数调用。对于绑定(bind),JavaScript引擎甚至需要进行该函数调用来设置属性值之前,还需要评估该绑定(bind)(还评估其依赖的其他内容)。

查看您的Flickable代码段,您将看到一个列的重复器,其中包含行的重复器。您说您最多允许使用150x150的网格。让我们对这个数字做一些粗略的数学运算。对于每个图块,您(至少)有两个矩形,一个图像和一个文本项,每个Tile.qml实例总共提供4个项。此外,每个行和一个中继器的固定成本。

这意味着网格上单行的总创建成本为:2 + (4 * mapSize)项,每行总共602个项。然后,将其乘以150,得出创建该网格的总成本为90,300。

每行也有许多绑定(bind):我在图块中计数9(在图块本身中计数7,不包括有些特殊的“id”分配,再加上两个x和y坐标),另外两个分别用于行和中继器绑定(bind),即每行2 + (9 * mapSize)绑定(bind)-每行1352个绑定(bind),整个网格的202,800个绑定(bind)。

总而言之,这是一次要使用的非常大量项目和绑定(bind)。

这些项目中的每一项都具有很高的成本-例如,每个项目本身到处都是一百字节,为您在每个项目上创建的绑定(bind)分配了额外的分配,为项目创建以实际获得 yield 的QSGNode实例的分配屏幕,并且使用Repeater也意味着您在JavaScript堆上为每个委托(delegate)分配了一些额外的分配...这全部可能会增加非常大的内存,具体取决于您一次创建多少东西。

因此,要直接回答您的问题,简单的答案是“不要创造太多东西”。我不确定您如何实现这一目标,但是有以下几种可能性:

  • 您可以将更多单独的Tile合并到Image中,例如矩形,只是像Image { Text { anchors.centerIn: parent } }这样的图块
  • 您可以考虑是否可以通过某种方式使用GridView来帮助您,但这会给您的设计带来一些限制。
  • 如果GridView不符合您的需求,我建议您最好写一个 View 项,负责创建和定位Tile实例,这样您只需为显示在的 map 部分实例化tile。任何给定的点。

  • 对于最后一个选项,它会像这样。您需要研究QQuickItem的子类化(在C++方面),并具有Q_PROPERTY(QQmlComponent* tileDelegate READ tileDelegate WRITE setTileDelegate NOTIFY tileDelegateChanged)。在setTileDelegate setter 中,调用QQuickItem::polish,然后覆盖QQuickItem::updatePolish,然后在其中创建(或重新放置)所提供tileDelegate组件的实例,该实例从屏幕上当前显示的位置偏移,直到“GameViewThing”再次完全被图块覆盖。

    我在这里有点含糊-抱歉-但是完整的示例将包含很多代码,所以我希望我已给您足够的信息和指导,使您能够自己开始。

    关于c++ - 大网格上的QML内存使用情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41609641/

    相关文章:

    c - free() 在 c 代码中收集垃圾值,即使在释放后将指针设置为 NULL,代码也不起作用

    c++ - 如何使用 Rational Rose 从源代码重新设计设计

    c++ - 程序在 VS 2013 中有效,但在 .exe 中无效

    java - Android——多个 Activity 、保持 Activity 状态并保存状态?

    iphone - 在 NSMutableArray 中保存 UIImage 的最佳实践

    c++ - 为什么QQuickWindow-> close()从rootObjects中删除对象?

    qt - 一种避免在 C++ 中定义 QObject 属性的样板代码的方法(可从 QML 访问)?

    qt - 每次从 qml 页面收到触摸事件时如何重置计时器

    c++ - !std::basic_ios::fail() 和 std::basic_ios::good() 有什么区别?

    C++ 运算符继承重载