如何在不导致内存泄漏的情况下使用QSGGeometryNode并确保正确清理

8
我使用了一个 QSGGeometry、QSGVertexColorMaterial 和一个 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完成之后。而那不在我的控制范围内。 问题: 如何确保2个指针materialchild_node正确地从内存中清除? 像我上面所做的child_node->setFlag(QSGNode::OwnsMaterial)一样,是否设置了指针的所有权到QtSceneGraph并使我免于删除指针的负担?
次要问题: 我正在使用oldNode->removeAllChildNodes()来清除前一帧中绘制的数据。这是在绘制新数据之前清除屏幕上先前数据的好方法吗?
附言: 我再次强调:这种实现没有性能问题。我只想确定我没有造成任何内存泄漏。我尝试将materialchild_node用作智能指针,如下所示:
auto material = std::make_shared<QSGVertexColorMaterial>();
auto child_node = new std::make_shared<QSGGeometryNode>();

但是当materialchild_node在稍后被自动清除内存时,这会导致崩溃。

1个回答

7

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

oldnode和child_node

从QQuickItem::updatePaintNode()返回的oldnode会在正确的时间和线程上自动删除。QSGNode实例树通过使用默认设置的QSGNode :: OwnedByParent进行管理。

material

因为您已经为child_node设置了QSGNode :: OwnsMaterial标志,所以在删除child_node时会同时删除其material

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

答案是否定的。每次场景被渲染时创建和删除节点没有意义。相反,您应该重用节点/节点。在下面的示例代码中,我假设几何图形在QQuickItem的生命周期内发生更改,但材料不变。如果材料更改,则可能需要调用node->markDirty(QSGNode :: DirtyMaterial)。请注意,只创建一个节点,并且仅在创建一次(除非例如窗口被隐藏然后重新带回前景或其他情况)。

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接