STL learning - On the Space Configurator

1. What is the space Configurator

        Configurator space definition is, for each work quietly efficient management container space (space applications and recovered). Although in the regular use of STL, you may not need it, but standing on the perspective of learning research, learning its implementation principles of our great help.

2. Why do you need space Configurator

Here Insert Picture Description
        In front of the simulation to achieve vector, list, map, unordered_map and other containers, where all space is required by the new application, although the code can be run properly, but the following deficiencies:

1.空间申请与释放需要用户自己管理,容易造成内存泄漏
2.频繁向系统申请小块内存块,容易造成内存碎片
3.频繁向系统申请小块内存,影响程序运行效率
4.直接使用malloc与new进行申请,每块空间前有额外空间浪费
5.申请空间失败怎么应对
6.代码结构比较混乱,代码复用率不高
7.未考虑线程安全问题

Hence the need to design an efficient memory management mechanism.

3. SGI-STL space configurator implementation principle

        Some shortcomings mentioned above, the most important is: frequently apply to small system memory caused. What is a small piece of that memory? SGI-STL 128 as small and large memory the memory boundary, the space allocation is divided into two structures, a large memory space allocation processing, two small memory space allocation processing. This article will introduce combined to achieve, one with STL containers a space configurator. Two will be added subsequent to the spatial configuration.

        A space configurator principle is very simple, direct malloc and free the package, and increases in C ++ set_new_handle thought .

Brief set_new_handler:

        set_new_handler allows customers to specify a function that is called when memory allocation can not be satisfied.
C / C ++ memory allocation using new and delete. When new application memory, you may encounter a situation is that memory is not enough, and this time will throw out of memory exception. Sometimes, we want to be able to call their own custom exception handler, which is to say this clause. In a statement in the standard library, there are the following interfaces:

1 namespace std
2 {
3     typedef void (*new_handler)();
4     new_handler set_new_handler(new handler p) throw();
5 }

        Note that there is a typedef the new_handler function pointer, which points to a function, the function returns a value of void, parameters are void. set_new_handler is to new_handler point to a specific function, which function in this process out of memory anomalies (throw the end of the function () indicates that it does not throw task exception), if this new_handler is empty, then this function is not implemented, it will throw out of memory exception.

 1 void MyOutOfMemory()
 2 {
 3     cout << "Out of memory error!" << endl;
 4     abort();
 5 }
 6 
 7 int main()
 8 {
 9     set_new_handler(MyOutOfMemory);
10     int *verybigmemory = new int[0x1fffffff];
11     delete verybigmemory;
12 }

        Here preset function well when abnormal new call is MyOutOfMemory, then intentionally apply a lot of memory, it will come MyOutOfMemory in coming.

Note : the substance of the first stage configurator is the use of malloc, realloc, free. The situation and deal with the lack of memory (memory request fails), as provided set_new_handler :: operator new operation, allowing users to process policy when insufficient memory occurs customize their own. SGI STL does not use the C ++ set_new_handler, so alone to achieve this functionality.

Given below to achieve a spatial filter configured :

template<int inst>
class _malloc_alloc_template
{
	/* oom_alloc为静态函数成员,用于处理malloc时的内存不足问题
	   oom_realloc为静态函数成员,用于处理realloc时的内存不足问题
	   _malloc_alloc_handler为静态数据成员,为void(*)()类型的函数指针,用于
	   //用户自己制定内存分配策略
	*/
	static void * oom_malloc(size_t);//out_of_memmory malloc
	static void * oom_realloc(void *, size_t);
	static void(*_malloc_alloc_oom_handler)();
public:
	static void * allocate(size_t n)
	{
		void * result = malloc(n);//请求内存
		if (result == nullptr)//如果内存不足
			result=oom_malloc(n);//调用oom_malloc
		return result;
	}
	static void * reallocate(void * p, size_t n)
	{
		void *result = realloc(n);
		if (result == nullptr)
			result = oom_realloc(p, n);
		return result;
	}
	static void deallocate(void * p)
	{
		//使用free函数释放p地址后所分配的内存块
		free(p);
	}
 
	/*此静态成员函数接受一个void(*)()类型的函数指针作为参数,返回
	void(*)()类型的函数指针。其作用为用用户自己定制的内存调度方法替换
	_malloc_alloc_handler,由此实现类似C++的set_new_handler方法。
	*/
 
	static void(* set_malloc_handler(void(*f)()))()
	{
		void(*old)() = _malloc_alloc_oom_handler;
		_malloc_alloc_oom_handler = f;
		return old;
	}
};
 
template<int inst>
void(*_malloc_alloc_template<inst>::_malloc_alloc_oom_handler)() = 0;
 
template<int inst>
void * _malloc_alloc_template<inst>::oom_malloc(size_t n)
{
	void(*my_oom_handler)();
	void * result;
	//无限循环,直至成功分配内存或用户没有定制内存分配策略
	for (;;)
	{
		my_oom_handler = _malloc_alloc_oom_handler;
		if (my_oom_handler == nullptr)//如果用户没有定制内存分配策略
			exit(1);
		(*my_oom_handler)();//使用用户定制的方法
		result = malloc(n);
		if (result)
			return result;
	}
}


template<int inst>
void * _malloc_alloc_template<inst>::oom_realloc(void * p, size_t n)
{
	//此函数的设计思路与oom_malloc如出一辙
	void(*my_oom_handler)();
	void * result;
	for (;;)
	{
		my_oom_handler = _malloc_alloc_oom_handler;
		if (my_oom_handler == nullptr)
			exit(1);
		(*my_oom_handler)();
		result = realloc(p,n);
		if (result)
			return result;
	}
}


4. Space binding configurator STL containers and packaging and space configurator

SGI two configurator

#ifdef __USE_MALLOC

typedef malloc_alloc alloc;
typedef malloc_alloc single_client_alloc;

#else
 
 // 二级空间配置器定义
#endif

        Due to the above problems, SGI designed two configurations, a configuration that is the first stage and second stage configurator. Meanwhile, in order freedom of choice, STL also provides a __USE_MALLOC macro, if it exists directly call the first stage configurator, or directly calls the second stage configurator. SGI is not defined macros, that default to the second stage configurator.

        By pre-selecting a named command alloc between the first stage or the second stage is arranged, and then provided to the second template class template type parameter:

template<typename T,class Alloc=alloc>
class vector
{
	...
};

        Since we set _malloc_alloc_template or _default_alloc_template configurator underlying space, so we also need a wrapper function designed so that it conforms to the conventional manner using the spatial configuration of the device, it can also be better encapsulation of the underlying implementation:


/*
simple_alloc为底层的内存分配类的外部包装,其成员全部调用_malloc_alloc_template
的成员
*/
template<typename T,class Alloc=alloc>
class simple_alloc
{
public:
	static T * allocate(void)
	{
		return (T *)Alloc::allocate(sizeof(T));
	}
	static T * allocate(size_t n)
	{//此allocate接受一个指定对象个数的参数n
		return n == 0 ? nullptr : (T *)Alloc::allocate(sizeof(T)*n);
	}
	static void deallocate(T * p)
	{
		Alloc::deallocate(p, sizeof(T));
	}
	static void deallocate(T * p, size_t n)
	{
		if (n != 0)
			Alloc::deallocate(p);
	}
};

So that we can use them like this:

template<typename T,class Alloc=alloc>
class vector
{
	typedef T value_type;
protected:
	typedef simple_alloc<value_type, Alloc> data_allocator;
	...
		void deallocate()
	{
		if (...)
			data_allocator::deallocate(start, end_of_storge - start);
	}
	...
};

Guess you like

Origin blog.csdn.net/tonglin12138/article/details/93653781