【问题标题】:Free memory used by a std::stringstd::string 使用的空闲内存
【发布时间】:2012-06-11 11:02:53
【问题描述】:

我有一个struct,看起来像这样:

struct queue_item_t {
    int id;
    int size;
    std::string content;
};

我有一个std::vector< queue_item_t >,其中填充了许多来自数据库查询的信息。

处理每个项目时,会从磁盘读取一个文件,并将其内容放入content 字符串成员中。该项目已处理(content 已解析),我在字符串上执行 .clear(),以免耗尽我所有的内存。

但是,这似乎并没有释放内存。我正在处理数十万个项目,最终,内存使用量将超过可用内存,并且应用程序被 Linux 杀死,原因是“内存不足”。

如何释放这些字符串使用的内存?

【问题讨论】:

  • 你需要content 作为结构的成员吗?根据您的解释,听起来它只是非常简短地使用,因此临时可能更适合该任务。此外,为什么不使用std::queue 而不是std::vector
  • 您的结构被称为queue_item_t 的事实表明它们的向量代表某种队列。如果是这种情况,为什么不在处理完元素后从队列中删除它们呢?我问,因为它可能是您的问题的正确解决方法在于其他地方。销毁它们(以及它们的content 字符串)是释放资源的一种非常可靠的方法!然后你只需要处理从向量的开头删除效率不高的事实 - 所以请改用deque,或者如果处理它们的顺序无关紧要,则以相反的顺序处理。跨度>
  • @SanderDeDycker 我现在做的只是整个过程的第二部分;在正常操作下,从不从文件中读取数据,而是从互联网上检索数据,并将数据直接放在已下载的每个项目的content字符串中。但你是对的,在不同的情况下,临时变量会更好。
  • 如果对于队列中的每个项目,您检索内容,处理内容,然后丢弃它,那么检索和处理的确切方法无关紧要。内容(甚至项目)在处理后仍会被丢弃,因此似乎不需要将其存储在队列中 - 它可以作为函数参数或类似参数传递。如果我遗漏了什么,有代表性的代码示例可能会很有用。

标签: c++ linux stdstring


【解决方案1】:

std::string 和 std::vector 在 clear() 中不改变容器容量(=> 不释放容器内存)。每当需要压缩时(通常不需要),都应使用以下临时对象技巧。

my_queue_item.content.clear(); // clear
std::string(my_queue_item.content).swap(my_queue_item.content); // compact

当需要清理+压缩时,上面的代码可以变得更简单:

std::string().swap(my_queue_item.content);

一些字符串实现是写时复制。这样的字符串,当从多个地方引用时,会在写入时重新分配内存。

【讨论】:

  • 而 C++11 添加了一个shrink_to_fit 成员函数,这是对实现做一些明智的非绑定请求。
  • @Luchian: clear 保证不会减少字符串的capacity,所以它几乎无法释放内存。
  • @SteveJessop 所以它只是用 0 替换所有字符?
  • @stefanbachert C++11 FDIS: 21.4.4/15 表示 clear(); 等于 erase(begin(), end());,而后者又在 21.4.6.5/9 中定义,字面意思是:removes the characters in the range [first,last)。这只会修改字符数组和end() 的位置,而不是已经分配的内存。
【解决方案2】:

clear 不会释放 all 字符串的内存(可能只是缓冲区)。它只会将字符串设置为空。

如果你可以在字符串上调用clear,为什么不重用它呢?因此,无需创建新的queue_item_t,只需将其字符串成员替换为新值即可。

【讨论】:

    【解决方案3】:

    要释放内存,您可以这样做:

    my_queue_item.content = "";
    my_queue_item.content.shrink_to_fit();
    

    shrink_to_fit() 方法将很好地释放内存并为 my_queue_item.content 的新值分配足够小的空间(本例为 15 个字节)。

    【讨论】:

    • 不幸的是,shrink_to_fit() 没有绑定,所以很可能会被忽略,这确实使它看起来是一个相当无意义的函数,而它本来可以是一个非常有用的函数。
    【解决方案4】:

    clear 可能不会释放内存。它会在逻辑上将字符串设置为空字符串,但可能不会影响已分配的内存。

    如果你正在读取更多数据到同一个queue_item_t,它应该替换之前的字符串内容。

    你确定你自己没有泄露queue_item_t吗?

    【讨论】:

      猜你喜欢
      • 2011-07-26
      • 2013-08-17
      • 2011-03-26
      • 2023-02-11
      • 1970-01-01
      • 2018-08-21
      • 2021-02-27
      • 2012-09-18
      • 2015-08-17
      相关资源
      最近更新 更多