如何使用QSGGeometryNode而不会导致内存泄漏并确保正确清理

时间:2017-09-24 19:44:44

标签: c++ qt qml scenegraph qsgclipnode

我使用QSGGeometryQSGVertexColorMaterial& QSGGeometryNode QQuickItem在我的MyQuickItem派生类中实时绘制一些内容updatePaintNode

以下是我的QSGNode * MyQuickItem::updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData) { if (!oldNode) { oldNode = new QSGNode; } oldNode->removeAllChildNodes(); QSGGeometry * geometry = GetMyGeometry(); QSGVertexColorMaterial * material = new QSGVertexColorMaterial; QSGGeometryNode * child_node = new QSGGeometryNode; child_node->setGeometry(geometry); child_node->setMaterial(material); child_node->setFlag(QSGNode::OwnsMaterial); oldNode->appendChildNode(child_node); return oldNode; } 方法,其中重绘逻辑的关键在于。

updatePaintNode

问题:
上面的逻辑效果很好。完全没有功能问题。也没有性能问题。 但我担心我会导致内存泄漏。请看上面方法QSGVertexColorMaterial * material = new QSGVertexColorMaterial; QSGGeometryNode * child_node = new QSGGeometryNode; 中的以下两行,我在其中分配原始指针。

updatePaintNode

我分配他们&我不删除它们。这是因为应该删除它们的点是在material完成之后。 那不受我的控制。

问题:
如何确保2个指针child_node& child_node->setFlag(QSGNode::OwnsMaterial)是否已正确清除记忆? 像我上面那样做oldNode->removeAllChildNodes()会将指针的所有权设置为QtSceneGraph&减轻我删除指针的负担?

次要问题:
我正在使用material来清除前一帧中绘制的数据。这是在绘制新数据之前清除屏幕上的先前数据的好方法吗?

PS:
我重申:此实现没有性能问题。我只是想确定我没有造成任何内存泄漏。我尝试过使用child_node&amp; auto material = std::make_shared<QSGVertexColorMaterial>(); auto child_node = new std::make_shared<QSGGeometryNode>(); 像智能指针一样:

material

但这会导致child_node&amp;稍后会从内存中自动清除--**First**---|--Second--|---Third--|--Fourth--| (scrolling categories) ------------------------------------------------------------------ \\\FirstA\\\ \\\FirstB\\\ \\\FirstC\\\ \\\FirstD\\\ \\\FirstA\\\ \\\FirstB\\\ \\\FirstC\\\ \\\FirstD\\\ ------------------------------------------------------------------

1 个答案:

答案 0 :(得分:4)

是的,在您的示例代码中,您可以依赖节点的自动清理。您没有从updatePaintNode泄漏内存。

oldnode和child_node

从QQuickItem :: updatePaintNode()返回的

oldnode会在正确的时间在右侧线程上自动删除。通过使用默认设置的QSGNode :: OwnedByParent来管理QSGNode实例的树。

<强>材料

因为你已经为你的child_node设置了标志QSGNode :: OwnsMaterial {child}删除了child_node时删除了material

第二个问题:这是一个好方法吗?

答案是否定的。每次渲染场景时都没有创建和删除节点的意义。相反,您应该重用节点/节点。在下面的示例代码中,我假设几何体发生了变化,但材料在QQuickItem的生命周期内没有变化。如果材料发生变化,您可能需要调用 node-&gt; markDirty(QSGNode :: DirtyMaterial)。请注意,只创建了一个节点,并且只创建了一个节点(除非窗口隐藏,然后再返回到fg或其他位置)。

QSGNode * MyQuickItem::updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData) {

    QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode);
    if (!node) {
        node = new QSGGeometryNode;

        QSGVertexColorMaterial * material = new QSGVertexColorMaterial;
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);
    }

    // if GetMyGeometry returns every time a new dynamically allocated object then you should
    // call node->setFlag(QSGNode::OwnsGeometry) to not leak memory here:
    QSGGeometry * geometry = GetMyGeometry(); 
    node->setGeometry(geometry);
    // No need to call node->markDirty(QSGNode::DirtyGeometry) because setGeometry is called.

    return node;
}
相关问题