【发布时间】:2012-04-28 07:45:56
【问题描述】:
我在 C++ Builder 中使用 VirtualTreeView 并使用如下结构:
struct TVTNodeData
{
int Index;
UnicodeString Caption;
}
我使用循环预填充树的节点:
TVirtualNode *Node = VTree->AddChild(NULL);
pNode = (TVTNodeData *)VTree->GetNodeData(Node);
pNode->Index = 1;
pNode->Caption = "Whatever";
我注意到应用程序的内存在不断增加(内存泄漏),即使我清除了树并重新加载它。此页面 - http://www.remkoweijnen.nl/blog/2010/06/09/memory-leaks-when-using-virtual-treeview-component/ 建议在 OnFreeNode 事件中执行 Finalize()。到目前为止还不错。
但是 C++ 中没有 Finalize()。我在OnFreeNode 事件中尝试了pNode->Caption="",内存不再分配得那么剧烈,但它仍然有点。我认为即使 UnicodeString 被清空(引用计数 > 0),也可能会留下对 UnicodeString 的引用。
如何在 C++ 中为 UnicodeString 释放 OnFreeNode 事件中的节点数据?我知道分配 UnicodeString 直到所有引用计数为零 - 那么如何强制引用计数为零?
另外,如果在OnNodeInit 中分配了节点怎么办 - 在OnFreeNode 事件中同样适用吗?
如果 TVTNodeData 结构是纯虚拟的 - 节点永远不可见,也不使用 AddChild 或 OnNodeInit 初始化,然后需要 Finalize,那么该结构甚至存在于内存中吗?
更新:后来我发现我测量内存使用率不正确,对于字符串,将它们设置为空字符串确实足以清除内存数据。但是 - 正如 Rob Kennedy 在下面的回答中所建议的那样,调用 struct ~destructor 甚至更好,等效于 Finalize 并且更容易,因为它清除了整个结构(如果你有更多的字符串)。
【问题讨论】:
-
您是否指定了正确的
NodeDataSize?还可以尝试验证您添加到树中的每个节点,WideString也是 Caption 的选项吗?。 -
是的,我在循环之前做了
VTree->NodeDataSize = sizeof(TVTNodeData);。 WideString 是可能的,但使用它有什么好处?它没有引用计数,因此将其设置为空字符串会释放所有内存吗? UnicodeString 不是对 VCL 更友好吗? -
WideString 是 COM BSTR 类型,由 Windows COM 堆分配器管理,没有引用计数。但简单地将 UnicodeString 设置为空字符串应该等于 Finalize。
-
谢谢,我发现毕竟没有泄漏。但是我确实发现 WideString 消耗的内存比 UnicodeString 少,你能确认一下吗?
-
是的,
WideString消耗的内存少于UnicodeString。Widestring除了字符数据之外只包含一个 4 字节整数(字符串长度),而UnicodeString包含两个 4 字节整数(字符串长度和引用计数)和两个 2 字节整数(元素除了字符数据之外,每个字符的大小 - 总是 2 - 和字符串代码页 - 总是CP_UTF16)。
标签: c++ delphi memory-leaks c++builder virtualtreeview