我需要减少本机 Windows C++ 应用程序使用的内存,而不影响其性能。
我的主要数据结构由数千个动态分配的实例组成,属于以下
Line
类:
struct Properties
{
// sizeof(Properties) == 28
};
// Version 1
class Line
{
virtual void parse(xml_node* node, const Data& data)
{
parse_internal(node, data);
create();
}
virtual void parse_internal(xml_node*, const Data&);
void create();
Properties p;
};
但是因为我注意到我可以摆脱类成员
p
,因为我只需要在解析方法中使用它,所以我更改了Line
实现:
// Version 2
class Line
{
virtual void parse(xml_node* node, const Data& data)
{
Properties p;
parse_internal(node, data, &p);
create(&p);
}
virtual void parse_internal(xml_node*, const Data&, Properties*);
void create(Properties*);
};
这减少了几兆字节的内存分配,但增加了超过 50 毫秒的运行时间。
我想知道考虑到该应用程序已编译为发布版本并完全启用了速度优化,这怎么可能。是因为论证通过了吗?难道是我的
struct Properties
的栈分配的问题?
更新:
方法
Line::parse
对于每个实例仅调用一次。数据结构由 std::vector
的 Line
组成。多个线程管理该向量的不同子集。
你写的parse_internal是递归的。这意味着它在更改后的变体中获得 3 个参数,而不是原始版本中的 2 个参数 - 并且会递归调用几次。
您还必须使用指针语法而不是元素取消引用来访问成员(并且可能验证 Properties 指针是否为非空)。要消除指针问题,您可以使用 parse_internal 的引用参数。
是否有理由将 parse_internal 作为虚拟成员函数,或者您可以将其更改为静态(在修改后的变体中)?
在实现的 first 版本中,
Properties p;
对象是 Line
class 中的全局变量,这意味着每次创建 Line
对象时都会创建它(正如您在评论中提到的那样,140k),并且仅当这些对象本身被破坏时才被破坏/取消分配。
在您的 second 版本的实现中,
Properties p;
对象是 parse()
function 中的局部变量,这意味着它在调用该函数时被初始化,并且也在该函数结束。
所以我的猜测是,当您测量整体性能时,您的
Version 2
,它包括在您的Version 1
测量期间的取消分配时间,它不被计算在内。
当然,您可以通过将
Properties p;
函数中的 parse()
对象声明为 static
来避免其被破坏,但在这种情况下,您的性能应该与您的第一次测量非常接近。
相反,为了提高整体性能,我建议您仅创建该
Properties p;
对象一次,返回到 Line
类中作为成员变量,但在 parse()
函数中进行更改/重新分配其内容(即这 28 个字节)适当。这样您就可以避免昂贵的对象实例化和取消分配时间。
顺便说一句,我希望你的28字节的
struct Properties
已经对齐了;)