2014-02-18 81 views
0

我正在使用内存优化,同时在向量中加载数据。我想知道向量重新分配时Vector所使用的内存会发生什么情况。我的意思是它是否由Vector释放?向量重新分配C++

thnaks提前。

+0

std :: vector不会留下旧的未使用的内存作为内存泄漏,如果这是你要求的。然而,这适用于C++以及C:http://stackoverflow.com/questions/1556014/memory-usage-isnt-decreasing-when-using-free/1556024#1556024 –

+0

我不认为标准保证任何事情,但是,一般来说,是的,当你超过当前容量时,向量将分配一个更大,连续的内存块并释放旧的块。 – Brian

+0

感谢您的输入Brian Bi和Thomas Padron-McCarthy,我在向量中存储了12个表格,它占用了83.8 MB RAM,但是当我使用vector.reserve()时,它花费了37.8MB RAM,这接近实际大小。一行vector.reserve(1000000)使这种差异,这就是为什么我想知道这一点。 –

回答

1

请记住,如果您基于“顶部”或“任务管理器”测量内存使用情况,则“释放”的内存不一定实际上“设置为消失”。大多数现代堆管理员并没有将内存一直释放到操作系统级别,因为预期分配一次的内存将再次需要。只有当释放的数量达到一定的限制(连续的范围内,所以如果在释放的记忆海中存在仍然使用的记忆的小“岛屿”,它不能作为一个块被释放,并且很可能留在你的应用程序“永远”)。

对此,你无能为力,只能忍受它。如果您事先知道需要多少内存,请使用reserve()来保留它。如果你不这样做,让它自己成长。内存被释放,它只是没有作为“自由内存”回馈给实际操作系统,它位于应用程序的堆中。如果整个系统的内存不足,那么未使用的内存将被换出,其他更有用的内容将被加载到内存中,因此它不会被“占用并且永远不能用于其他任何事情” 。 (当然,如果你有很多使用内存的岛屿不时被访问,那么很可能内存不能被重用)。

1

我不允许由于较少的信誉发表评论,但你可能会有所帮助:

c++ Vector, what happens whenever it expands/reallocate on stack?

+2

这个想法是,你通过写出很好的答案和/或问题来获得足够的声誉,而不是将评论添加为答案。 – juanchopanza

+0

@juanchopanza我完全同意!但是那样我想贡献,但实际上不允许;这听起来不够好!现在我有权发表评论,我也会遵循。应该这样,如果某人在任何合作伙伴网站上拥有最低限度的声誉,应该允许他在所有其他网站上执行该操作。 – CinCout

1

未能释放内存,它不再使用将是一个很明显的错误在执行的std::vector。当然,错误的确发生了,所以你几乎不可能找到这样一个实现的问题,但是你通常会认为vector经过了相当好的测试,所以找到这样的东西似乎是不太可能的(如果你这样做的话,它可能会只是在相对模糊的情况下发生的事情)。

当然,vector使用Allocator参数(默认为std::allocator<T>)来执行实际分配和释放内存(等等)。因此,分配器类中的错误可能导致内存不能按预期方式释放。假设你使用std::allocator<T>,我会很惊讶地看到这种情况发生,但是如果(例如)你使用别人的分配器类,问题可能会更有可能(分配器类的接口不是立即显而易见的,关于它的良好文档并不特别常见)。

在我看到的大多数(最近)实现中,vector在空间不足时扩展了1.5倍。如果该因子小于中间值(〜1.6),并且先前的分配彼此连续,则它们(最终)将合计为可以满足稍后要求的块。如果因素大于中庸,他们永远不会。

+0

如果std :: allocator使用与malloc()类似的OS接口,那么在每次删除(或免费)时,它并不总是将内存返回给操作系统。如果它足够大以处理稍后的分配,它将重用一个“不确定”的内存块。 – rcgldr

2

例如,这是gcc 4.8中的矢量调整大小实现。2:

void resize(size_type __new_size) 
    { 
    if (__new_size > size()) 
     _M_default_append(__new_size - size()); 
    else if (__new_size < size()) 
     _M_erase_at_end(this->_M_impl._M_start + __new_size); 
    } 

因此,如果新的大小比电流矢量大小,_M_default_append被称为:

template<typename _Tp, typename _Alloc> 
void vector<_Tp, _Alloc>::_M_default_append(size_type __n) 
{ 
    if (__n != 0) 
    { 
     if (size_type(this->_M_impl._M_end_of_storage 
        - this->_M_impl._M_finish) >= __n) 
     { 
      std::__uninitialized_default_n_a(this->_M_impl._M_finish, 
              __n, _M_get_Tp_allocator()); 
      this->_M_impl._M_finish += __n; 
     } 
     else // if new size is larger, execution flow goes here 
     { 
      //get size of a new memory block allocated for internal storage 
      const size_type __len = 
      _M_check_len(__n, "vector::_M_default_append"); 
      const size_type __old_size = this->size(); 
      //allocate new memory block 
      pointer __new_start(this->_M_allocate(__len)); 
      pointer __new_finish(__new_start); 
      __try 
      { 
       //move existing elements to a new memory if stored objects are movable 
       //or just copy them 
       __new_finish 
       = std::__uninitialized_move_if_noexcept_a 
       (this->_M_impl._M_start, this->_M_impl._M_finish, 
       __new_start, _M_get_Tp_allocator()); 
       //create new elements at the end of the storage 
       std::__uninitialized_default_n_a(__new_finish, __n, 
               _M_get_Tp_allocator()); 
       __new_finish += __n; 
      } 
      __catch(...) 
      { 
       // if exception was thrown while coping, destroy elements in new storage 
       // and throw exception again 
       std::_Destroy(__new_start, __new_finish, 
          _M_get_Tp_allocator()); 
       // deallocate new memory 
       _M_deallocate(__new_start, __len); 
       __throw_exception_again; 
      } 
      // call destructors of the elements in the old storage 
      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, 
         _M_get_Tp_allocator()); 
      // deallocate memory used for the old storage 
      // _M_deallocate here checks if _M_start is not null and 
      // calls allocator's deallocate method 
      _M_deallocate(this->_M_impl._M_start, 
         this->_M_impl._M_end_of_storage 
         - this->_M_impl._M_start); 
      // set new storage to this vector object 
      this->_M_impl._M_start = __new_start; 
      this->_M_impl._M_finish = __new_finish; 
      this->_M_impl._M_end_of_storage = __new_start + __len; 
     } 
    } 
} 

所以,你可以看到,载体使用分配器的deallocate方法来删除旧的存储。如果这是默认的std :: allocator,则它在内部使用newdelete运算符。该运营商通常会拨打malloc/free方法。一些malloc实现有工具来分析堆和检测内存错误,也有一些选项可以禁用内部区域的内存缓存,所以当free被调用时,你可以使它返回内存到操作系统。见tcmallocjemalloc