将std :: vector <char>截断为长度N的有效方法 - 释放内存</char>

时间:2014-08-16 00:40:28

标签: c++ windows vector stl stdvector

我有几个chad的大型std ::向量(从二进制文件加载的字节)。

当我的程序内存不足时,我需要能够剔除这些向量使用的一些内存。这些向量几乎是我内存使用的全部内容,它们只是本地和网络文件的缓存,所以只抓住最大的一个并将其切成两半左右是安全的。

唯一的问题是,我目前正在使用vector :: resize和vector :: shrink_to_fit,但这似乎需要更多内存(我想要重新分配新大小)然后一堆时间(用于销毁现在被破坏的指针,我认为是免费的?)然后将剩余的复制到新的向量。请注意,这是在Windows平台上,在调试中,因此指针可能不会在发布版本或其他平台上销毁。

我能做些什么来说“C ++,请告诉操作系统我不再需要位于此向量中位置N的内存”?

或者,是否有另一个容器我最好使用?我确实需要随机访问,或者努力设计一种方法来轻松地将迭代器指向我接下来想要阅读的地方,这是可能的,只是不容易,所以我不想使用std ::列表。

2 个答案:

答案 0 :(得分:4)

resizeshrink_to_fit是你最好的选择,只要我们谈论的是标准的C ++,但是如果你处于低内存状态开始,你会注意到它们可能根本不起作用with:由于分配器接口不提供类似realloc的操作,因此向量被强制分配新块,复制其中的数据并释放旧块。

现在,我基本上看到了四种简单的方法:

  • 删除整个向量,而不仅仅是它们的一部分,可能使用LRU或类似的东西;使用大向量,C ++分配器通常只是转发到操作系统的内存管理调用,因此内存应该直接返回操作系统;
  • 编写您自己的容器,该容器使用malloc / realloc或特定于操作系统的功能;
  • 使用std::deque代替;你失去了保证数据的连续性,但是,由于deques通常会为不同的块中的数据分配空间,所以执行resize + shrink_to_fit应该非常便宜 - 只需释放最后所有未使用的块,无需大规模重新分配;
  • 将这份工作留给操作系统。正如评论中已经说明的那样,操作系统已经有了文件缓存,在正常情况下,它可以比你或我更好地处理它,即使只是因为它可以更好地了解物理留下内存,大多数应用程序的文件“热”,等等。此外,由于您在虚拟地址空间中工作,您甚至无法保证您的内存实际上将保留在RAM中;当机器进入内存压力并且你不经常使用某些内存页时,它们会被交换到磁盘,所以你的所有性能提升都会丢失(并且你已经找到的东西在页面文件上浪费了空间在磁盘上)。

另一种方法可能是使用内存映射文件 - 系统将照常执行自己的缓存,但只要文件保留在内存中,就可以避免任何系统调用开销。

答案 1 :(得分:2)

std :: vector :: shrink_to_fit()不会导致使用更多内存,如果是这样,它就是一个错误。

C ++ 11定义了shrink_to_fit(),如下所示:

void shrink_to_fit();备注:shrink_to_fit是一个将capacity()减小为size()的非绑定请求。 [注意:请求是非绑定的,以允许特定于实现的优化的纬度。 - 结束说明]

正如注释所示,shrink_to_fit()可能(但不一定)实际上是空闲内存,并且该标准使C ++实现可以随心所欲地在内部回收和优化内存使用,正如他们认为的那样。 C ++没有强制要求shrink_to_fit()等导致实际内存被释放到操作系统,并且在很多情况下,C ++运行时库实际上可能无法实现,因为我会到达一会儿。允许C ++运行时库获取释放的内存,并将其存储在内部,并自动重用它以用于将来的内存分配请求(显式新闻或容器增长)。

大多数现代操作系统不是为分配和释放任意大小的内存块而设计的。细节不同,但通常操作系统在偶数块中分配和释放内存,通常是4Kb或更大,甚至是内存页面地址。如果你分配一个长度只有几百个字节的新对象,那么C ++库将请求分配整页内存,为新对象取出前100个字节,然后保留备用数量。记忆未来的新请求。

类似地,即使shrink_to_fit()或者delete,释放了几百个字节,它也不能立即回到操作系统,但只有当整个4kb的连续内存范围(或任何分配)时操作系统使用的页面大小) - 适当对齐 - 完全未使用。只有这样,进程才能将该页面释放回操作系统。在此之前,库会跟踪释放的内存范围,以用于将来的新请求,而无需要求操作系统为进程分配更多内存页。