Vector memory mechanism and performance analysis

Source: Internet
Author: User
Tags throw exception
Some good company campus recruitment process (including written test, interview link), often involves the use of vector in STL (mainly written) and its performance (interview) analysis. Read the relevant article today, but also wrote a few small test program ran run. As a summary, hope to help people in need.

About vectors, it's simply a dynamic array, there is a pointer to a continuous memory space, when the space is not enough to install the data will automatically apply for a larger space, and then copy the original data in the past, and then release the original piece of space, when the release or delete the data inside, Its storage space is not released, just empty the data inside. Next, I'll talk about that in more detail.

Note: The relevant programs in this article are tested in Windows 7+vs2008 environments. first, look at the vector's memory allocation mechanism:

Vector<int> arr;
Ofstream WF ("1.txt");
for (int i=0;i<100;++i)
{
	arr.push_back (i);
	wf<< "capacity=" <<arr.capacity () << ", size=" <<arr.size () <<end;
}
Wf.close ();
Capacity () returns the amount of space that is actually requested for the current vector object buffer (the memory space maintained by the vector after it is called a buffer), and size () returns the number of data stored in the current object buffer, and the capacity is always greater than or equal to size. The vector expands when size and capacity continue to add data when they are equal.

And look at the data in 1.txt:

Capacity=1,size=1
capacity=2,size=2
Capacity=3,size=3
Capacity=4,size=4
Capacity=6,size=5
Capacity=6,size=6
Capacity=9,size=7
Capacity=9,size=8
Capacity=9,size=9
capacity=13,size=10
capacity=13,size=11
Capacity=13,size=12
Capacity=13,size=13
Capacity=19,size=14
Capacity=19,size=15
Capacity=19,size=16
Capacity=19,size=17
Capacity=19,size=18
Capacity=19,size=19
Capacity=28,size=20
Capacity=28,size=21
Capacity=28,size=22
Capacity=28,size=23
Capacity=28,size=24
Capacity=28,size=25
Capacity=28,size=26
Capacity=28,size=27
Capacity=28,size=28
capacity=42,size=29
Capacity=42,size=30
Capacity=42,size=31
Capacity=42,size=32
Capacity=42,size=33
Capacity=42,size=34
Capacity=42,size=35
capacity=42,size=36
capacity=42,size=37
capacity=42,size=38
capacity=42,size=39
Capacity=42,size=40
Capacity=42,size=41
Capacity=42,size=42
capacity=63,size=43
Capacity=63,size=44
Capacity=63,size=45
Capacity=63,size=46
capacity=63,size=47
capacity=63,size=48
capacity=63,size=49
Capacity=63,size=50
capacity=63,size=51
capacity=63,size=52
capacity=63,size=53
capacity=63,size=54
Capacity=63,size=55
capacity=63,size=56
capacity=63,size=57
capacity=63,size=58
capacity=63,size=59
Capacity=63,size=60
capacity=63,size=61
capacity=63,size=62
capacity=63,size=63
Capacity=94,size=64
Capacity=94,size=65
capacity=94,size=66
capacity=94,size=67
capacity=94,size=68
capacity=94,size=69
Capacity=94,size=70
capacity=94,size=71
capacity=94,size=72
capacity=94,size=73
capacity=94,size=74
Capacity=94,size=75
capacity=94,size=76
capacity=94,size=77
capacity=94,size=78
capacity=94,size=79
Capacity=94,size=80
capacity=94,size=81
capacity=94,size=82
capacity=94,size=83
capacity=94,size=84
capacity=94,size=85
Capacity=94,size=86
capacity=94,size=87
capacity=94,size=88
capacity=94,size=89
Capacity=94,size=90
capacity=94,size=91
capacity=94,size=92
capacity=94,size=93
capacity=94,size=94
Capacity=141,size=95
capacity=141,size=96
capacity=141,size=97
Capacity=141,size=98
capacity=141,size=99
capacity=141,size=100

The data is a little bit more, and it's like this:

Capacity=1
capacity=2
Capacity=3
Capacity=4
Capacity=6
Capacity=9
Capacity=13
Capacity=19
Capacity=28
Capacity=42
capacity=63
capacity=94
capacity=141

See the rules. Yes, every expansion is an increase of 50% of the current space (except for the first time);

9+9/2=13;13+13/2=19;19+19/2=28 ...

In fact, the source code of the STL we can see, specifically in the compiler directory you said installed, for example, my VS2008 is in: Installation directory \vc\include below. You can also select the #include <vector> right key in vs to open. Of course, Windows on the STL source code are P.J. Plauger wrote (PS: Very cow B doctor, Baidu you know), we all said that the readability is very bad, I also think so, we rookie or see GCC in the STL source code.

This is the expansion of the \vc\include\vector:

if (_count = = 0)//here is judged, but do nothing, do not know why ...
			else if (max_size ()-size () < _count)//The compiler can request the maximum capacity not fit, throw exception _throw (Length_error, "vector<t> too Long");	_xlen (); Result too long else if (_capacity < size () + _count)//insufficient current space required for expansion {//Not enough room, reallocate _capacit y = max_size ()-_capacity/2 < _capacity?	0: _capacity + _capacity/2; Try to grow by 50%, the expansion 50% if (_capacity < size () + _count)//expansion 50% is still not enough, so that capacity equals the number of current data plus the number of new data _capacity = size
			() + _count;

			Pointer _newvec = This->_alval.allocate (_capacity);//apply for new space pointer _ptr = _newvec;	_try_begin _ptr = _umove (_myfirst, _vec_iter_base (_where), _newvec);	Copy prefix <span style= "white-space:pre" > </span>//copy the original data into the new memory _ptr = _ucopy (_first, _last, _ptr); Add new Stuff<span style= "White-space:pre" > </span>//copy Add data to the back of the new Memory _umove (_vec_iter_base (_where), _	Mylast, _ptr); Copy suffix _catch_all _destroy (_newvec, _ptR);
			This->_alval.deallocate (_newvec, _capacity);//Release the memory of the original application _reraise; _catch_end
Yes, that's 50% per expansion. As for deleting the data in the container, the buffer size does not change, only the data in it is clear, and the vector will automatically release the buffer only when the destructor calls.

Look at the destructor code:

	~vector ()
		{	//Destroy the Object
		_tidy ();
		}
void _tidy ()
{//FREE all storage
if (_myfirst!= 0)
{//Something to free, destroy and deallocate it


#if _has_iterator_debugging
This->_orphan_all ();
#endif/* _has_iterator_debugging *


_destroy (_ Myfirst, _mylast);/should be destroying every element of the vector
this->_alval.deallocate (_myfirst, _myend-_myfirst);/free space for the buffer
}
_myfirst = 0, _mylast = 0, _myend = 0;//pointer all to zero
}
Well, we can force the buffer to be freed when needed.

second, how to force the release of the vector buffer:

The answer is yes, and since the destructor frees up space, then we can invoke the destructor in a different way.

 	//Method I.,
 	Vector<int> (). Swap (arr); After Exchange
	//Method Two,
	{
		vector<int> temp;//temporary object is uninitialized, its buffer size is 0, no data
		arr.swap (temp);//Exchange data with our objects, The arr buffer is gone.
	}//temporary variable will be destructor, temp call vector destructor free space
third, how to use to improve performance:

In order to compare, we used three ways to put 100 data into the vector, respectively: 1, directly each time push_back () 2, using resize () to allocate 100 space in advance, and then push_back;3, Use reserve to allocate 100 storage space in advance. In MSDN, the descriptions of these two functions are:

Reserve reserves a minimum length of storage for vector object, allocating space if necessary.

Resize specifies a new size for a vector.

We use the same feeling when we initialize it here.

clock_t Start=clock ();
	for (int num=0;num<10000;++num)
	{
		vector<int> v1;
		for (int i=0;i<100;++i)
			v1.push_back (i);
	}
	cout<< "Direct Push Loop 10,000 times:" <<clock ()-start<<endl;
	Start=clock ();
	for (int num=0;num<10000;++num)
	{
		vector<int> v2;
		V2.resize (m);
		for (int i=0;i<100;++i)
			v2.push_back (i);
	}
	cout<< "Resize preset size before push cycle 10,000 times:" <<clock ()-start<<endl;
	Start=clock ();
	for (int num=0;num<10000;++num)
	{
		vector<int> v3;
		V3.reserve (m);
		for (int i=0;i<100;++i)
			v3.push_back (i);
	}
	cout<< "first reserve preset size and push cycle 10,000 times:" <<clock ()-start<<endl;

The results are different.


Reserve just keep a minimum space size, and resize is to redistribute the buffer, which involves a lot of judgment and memory processing, of course, here because the original is empty so the difference is not big.

The difference between the two views: the difference between Vector::reserve and vector::resize.

This shows that the number of data can be determined when the first preset space size is very necessary. Direct push_back data is time-consuming (of course, the data is small to ignore).


The complete code for the entire test program is as follows

#include "stdafx.h" #include "btree.h" #include <vector> #include <iostream> #include <Windows.h>
Include <fstream> #include <time.h> using Std::ofstream;
Using Std::cout;
Using Std::endl;
Using Std::vector; int _tmain (int argc, _tchar* argv[]) {/************************************************************************//* How vector forces free memory space////////////************************************************************ only when destructor is released/*
	/vector<int> arr;
	cout<< "When the default is not initialized, capacity=" <<arr.capacity () <<endl;
	Arr.resize (100,100);
	Arr.reserve (50);
	Arr.resize (50);
	cout<< "Now, capacity=" <<arr.capacity () <<endl;
	Vector<int>::iterator Itor=arr.begin () +10;
	Arr.erase (Arr.begin (), itor);
cout<< "capacity=" <<arr.capacity () << ", size=" <<arr.size () <<endl; Method one, vector<int> (). Swap (arr);
		Force free Space//Method II, {vector<int> temp;
	Arr.swap (temp); }//Temporary variables aredestructor cout<< "capacity=" <<arr.capacity () << ", size=" <<arr.size () <<endl;
	clock_t Start=clock ();
		for (int num=0;num<10000;++num) {vector<int> v1;
	for (int i=0;i<100;++i) v1.push_back (i);
	cout<< "Direct Push Loop 10,000 times:" <<clock ()-start<<endl;
	Start=clock ();
		for (int num=0;num<10000;++num) {vector<int> v2;
		V2.resize (100);
	for (int i=0;i<100;++i) v2[i] = i;
	cout<< "Resize preset size before push cycle 10,000 times:" <<clock ()-start<<endl;
	Start=clock ();
		for (int num=0;num<10000;++num) {vector<int> v3;
		V3.reserve (100);
	for (int i=0;i<100;++i) v3.push_back (i);
	} cout<< "Reserve preset size and push cycle 10,000 times:" <<clock ()-start<<endl;
	Vector<int> v4;
	Ofstream WF ("2.txt");
	int nflag=v4.capacity ();
		for (int i=0;i<100;++i) {v4.push_back (i);
			if (nflag!=v4.capacity ()) {nflag=v4.capacity ();
			cout<< "New buffer size=" <<nFlag<<endl; wf<< "CapacIty= "<<nFlag<<endl;
	} wf.close ();
	cout<< "max_size=" <<arr.max_size () <<endl;
return 0; }

Refer to some of the predecessors of the article, limited capacity, welcome advice, learn from each other.




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.