向量重新分配C ++

时间:2014-02-18 07:57:18

标签: c++ stl

我在向Vector中加载数据时正在进行内存优化。我想知道Vector重新分配时Vector使用的内存会发生什么。我的意思是它是否被Vector释放了?

提前th。不前。

4 个答案:

答案 0 :(得分: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;
        }
    }
}

因此,正如您所看到的,vector使用allocator的deallocate方法来删除旧存储。如果这是默认的std :: allocator,它会在内部使用newdelete运算符。此运算符通常调用malloc / free方法。一些malloc实现具有分析堆和检测内存错误的工具,还有一些可以选择在内部竞技场中禁用内存缓存,因此您可以在调用free时将内存返回到OS。请参阅tcmallocjemalloc

答案 1 :(得分:1)

由于声誉较低,我不允许发表评论,但您可能会觉得这很有用:

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

答案 2 :(得分:1)

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

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

对于它的价值,在我看到的大多数(最近的)实现中,vector在空间不足时扩展了1.5倍。如果因子小于黄金均值(~1.6)并且先前的分配彼此相邻,则它们(最终)将加起来以满足后来的要求。如果因子大于黄金均值,他们永远不会。

答案 3 :(得分:1)

请记住,如果您根据“top”或“任务管理器”测量内存使用情况,则“释放”的内存实际上并不一定“已经消失”。大多数现代堆管理器不会将内存一直释放到操作系统级别,因为期望再次需要分配一次的内存。只有一旦释放的量达到一定的限度(连续范围,所以如果在释放的记忆海洋中仍然使用的记忆的小“岛”,它不能被释放为一个块,并且很可能会留在你的申请“永远”)。

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