草庐IT

c++ - std::vector 增加峰值内存

coder 2024-02-19 原文

这是我上一个问题的延续。我无法理解 vector 占用的内存。问题骨架:

考虑一个 vector ,它是列表的集合,而列表是指针的集合。完全像:

std::vector<std::list<ABC*> > vec;

ABC 是我的类(class)。我们在 64 位机器上工作,所以指针的大小是 8 个字节。

在我的项目流程开始时,我将这个 vector 的大小调整为一个数字,以便我可以将列表存储在各自的索引中。

vec.resize(613284686);

此时, vector 的容量和大小为 613284686。对。调整大小后,我将列表插入相应的索引处:

// Some where down in the program, make these lists. Simple push for now.
std::list<ABC*> l1;
l1.push_back(<pointer_to_class_ABC>);
l1.push_back(<pointer_to_class_ABC>);

// Copy the list at location
setInfo(613284686, l1);

void setInfo(uint64_t index, std::list<ABC*> list>) {
  std::copy(list.begin(), list.end(), std::back_inserter(vec.at(index));
}

好的。这样插入就完成了。值得注意的是:

vector 的大小是:613284686 vector 中的条目是:3638243731//通过遍历 vector 索引并在每个索引处添加 std::lists 的大小来计算。

现在,由于有 3638243731 个指针条目,我预计此 vector 占用的内存约为 30Gb。 3638243731 * 8(字节)= ~30Gb。

但是但是当我在内存中有这些数据时,内存峰值达到 400G。

然后我用以下方法清理这个 vector :

std::vector<std::list<nl_net> >& ccInfo = getVec(); // getVec defined somewhere and return me original vec.
std::vector<std::list<nl_net> >::iterator it = ccInfo.begin();
for(; it != ccInfo.end(); ++it) {
  (*it).clear();
}

ccInfo.clear(); // Since it is an reference
std::vector<std::list<nl_net> >().swap(ccInfo); // This makes the capacity of the vector 0.

嗯,清理完这个vector,内存降到100G。从 vector 中持有的东西太多了。

你们都愿意纠正我这里不理解的地方吗?

附言我无法在较小的情况下重现它,但它会出现在我的项目中。

最佳答案

vec.resize(613284686);

At this point, capacity and size of the vector would be 613284686

至少 613284686。可能更多。

std::vector<std::list<nl_net> >().swap(ccInfo); // This makes the capacity of the vector 0.

技术上,标准不能保证默认构造的 vector 的容量不为 0...但在实践中,这可能是正确的。

Now, since there are 3638243731 entries of pointers, I would expect memory taken by this vector is ~30Gb. 3638243731 * 8(bytes)

但是 vector 不包含指针。它包含 std::list<ABC*>对象。所以,你应该期待 vec.capacity() * sizeof(std::list<ABC*>) vector 本身的缓冲区使用的字节。每个列表至少有一个指向开始和结束的指针。

此外,您应该期望每个列表中的每个元素也使用内存。由于列表是双向链接的,您应该期望每个元素有两个指针加上数据(第三个指针)的内存。

此外,列表中的每个指针显然都指向一个 ABC对象,每个都使用 sizeof(ABC)内存也是如此。

此外,由于链表的每个元素都是单独分配的,并且每个动态分配都需要簿记以便它们可以单独取消分配,并且每个分配都必须对齐到最大 native 对齐方式,并且自由存储在执行过程中可能会产生碎片,每次动态分配都会有很多开销。

Well, after clearing up this vector, memory drops down to 100G.

语言实现保留它从操作系统分配的(一些)内存是很典型的。如果您的目标系统记录了用于显式请求释放此类内存的实现特定函数,那么您可以尝试使用它。

然而,如果 vector 缓冲区不是最新的动态分配,那么它的释放可能会在空闲存储中留下大量可重用区域,但如果存在后来的分配,那么所有内存可能无法释放回操作系统。

即使语言实现已将内存释放给操作系统,操作系统通常会为进程保留内存映射,直到另一个进程实际需要内存用于其他用途。因此,根据您衡量内存使用情况的方式,结果可能不一定有意义。


可能有用的一般经验法则:

  • 除非您使用所有(或大部分)索引,否则不要使用 vector 。如果您不这样做,请考虑使用稀疏数组(尽管没有用于此类数据结构的标准容器)。
  • 使用 vector 时,如果知道分配的上限,请在调整大小之前保留。
  • 不要在没有充分理由的情况下使用链表。
  • 不要依赖于从峰值使用中恢复所有内存(返回操作系统;内存仍可用于进一步的动态分配)。
  • 不要强调虚拟内存的使用。

关于c++ - std::vector 增加峰值内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57405237/

有关c++ - std::vector 增加峰值内存的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  4. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. 键删除后 ruby​​ 哈希内存泄漏 - 2

    你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p

  8. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  9. ruby-on-rails - HTTParty 的内存问题和下载大文件 - 2

    这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e

  10. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

随机推荐