C ++ tecnología de gestión de memoria

C ++ primitivas membery

asignación liberación categoría podría sobrecargar
malloc gratis función C no se puede
nuevo Eliminar expresiones C ++ no se puede
:: nuevo operador :: operator delete función C ++ lata
asignador <T> :: asignar asignador <T> :: deallocate C ++ Standard Library Puede ser diseñado libremente para que coincida con cualquier contenedor
  • El cuarto método tiene diferentes formas en diferentes versiones del compilador
#ifdef _MSC_VER
    int *p4 = allocator<int>().allocate(3, (int*)0);
    allocator<int>().deallocate(p4, 3);
#endif

#ifdef __BORLANDC__
    int *p4 = allocator<int>().allocate(5);
    allocator<int>().deallocate(p4, 5);
#endif

#ifdef __GNUC__
    // 在早期的 GUNC 中使用这种调用方法
    void *p4 = alloc::allocate(512);
    alloc::deallocate(p4, 512);
    // 在后期的 GUNC 中进行了进一步的优化和区分
    int *p4 = allocator<int>().allocate(7);
    allocator<int>().deallocate((int*)p4, 7);
    // 而早期的 alloc 仍然十分重要,于是换成了这种写法
    void *p5 = __gnuc_cxx::__pool_alloc<int>().allocate(9);
    __gnuc_cxx::__pool_alloc<int>().deallocate((int*)p5, 9);
#endif

nueva / expresión de borrado

nueva asignará memoria, y luego llamar al constructor, por lo que la realización concreta de la nueva sigue, pero por lo general sobrecargado nuevo, están sobrecargados :: operador de nuevo

Complex *pc = new Complex(1, 2);
            ↓↓
try {
    void *mem = operator new(sizeof(Complex));// operator new 的实现调用了 malloc
    pc = static_cast<Complex*>(mem);
    pc->Complex::Complex(1, 2);
    // 在 GCC 中用户无法直接使用构造函数
} catch(std::bad_alloc) {
}

delete pc;
    ↓↓
pc->Complex::~Complex();
operator delete(pc);    // operaotr delete 的实现调用了 free

array nuevo / borrado

Mediante la apertura de una nueva matriz asignará una matriz de 4 bytes en la posición inicial de la galleta, una galleta que registra la longitud de la matriz de dispensación. Si utiliza la liberación de eliminación sólo dará a conocer uno de ellos, el otro bloque de pérdida de memoria mientras se está utilizando la liberación de borrado [], puede aplicar para asegurarse de que la memoria está completamente liberado.

Proceso para la construcción de matrices y se elimina, de acuerdo con la secuencia estándar de llamar a un constructor 0,1,2, 2,1,0 mesa de la prensa llamar secuencialmente el destructor.

nueva ubicación

la colocación de nuevo nos permite construir un objeto en una memoria ya asignados

char *buf = new char[sizeof(Complex)*3];
Complex *pc= new(buf)Complex(1, 2);
            ↓↓
try {
    void *mem = operator new(sizeof(Complex), buf);
    // 和 new 不同的地方在于多传了 buf 参数,于是 operator new 什么也不做直接返回 buf
    pc = static_cast<Complex*>(mem);
    pc->Complex::Complex(1, 2);
} catch(std::bad_alloc) {
}

clase asignar

malloc había cuatro bytes de memoria de galletas en la asignación de un extremo a otro, el tamaño de grabación de la memoria asignada. Por lo tanto, la memoria malloc frecuente hará que una gran parte de los residuos.

Solución técnica de este enfoque es a través de la técnica de agrupación de memoria, una gran I desechable puede asignar memoria para asignar memoria en el proceso posterior, una parte de la dispensado para el uso de la mayor parte del programa.

  • La primera edición de las técnicas de gestión de memoria son como sigue
class Screen{
public:
	static void* operator new(size_t size) {
		Screen *p;
		if(!freeStore){	// 如果没有可以用的内存空间,则再分配一次
			size_t chunk = screenChunk * size;
			freeStore = p = reinterpret_cast<Screen*> (new char[chunk]);	// char 字节为 1
			for(; p != &freeStore[screenChunk - 1]; ++ p){
				p -> next = p + 1; // 将得到的内存串成链表
			}
			p -> next = NULL;
		}
		p = freeStore;
		freeStore = freeStore -> next;
		return p;
	}
	static void operator delete(void *p) {
		(static_cast<Screen*>(p))->next = freeStore;
        // 显然,把 delete 掉的内存空间直接插入到头部,是最快的插入方式
		freeStore = static_cast<Screen*>(p);
	}
private:
    Screen *next;
    static Screen *freeStore;	// 将可用内存用链表形式存储,存下链表头指针
    static const int screenChunk;	// 选择一次性分配的内存空间
private:
    int i;
    /* 在第二版中,使用如下方法
    union {
        int i;
        Screen *next;
    }
        因为 next 只有在没有使用的时候才有意义,i 只有在被使用的时候才有意义,所以可以使用 union 来节省内存的消耗
    */
};
Screen* Screen::freeStore = NULL;
const int Screen::screenChunk = 24;
int main() {
	// freopen("in", "r", stdin);
	Screen *p[100];
	for(int i=0; i<100; i++) {
		p[i] = new Screen;
	}
	cout << "size of Screen " << sizeof(Screen) << endl;
	for(int i=0; i<10; i++) {
		cout << "address of p[" << i << "] " << p[i] << endl;
	}
	return 0;
}
  • La segunda versión es similar a la primera versión, pero agregó que la optimización de la unión.
  • Las dos primeras versiones de las operaciones de asignación de memoria se implementan dentro del objeto, pero de escritura para cada objeto de una asignación de memoria es claramente no es realista, la tercera versión del proceso de asignación de memoria se ha de extraer, encapsulado en una sola clase asignar en este asignar memoria contiene para cada clase, y después llama a la función asignar se completa el proceso de dispensación.

nuevo manejador

Cuando el nuevo operador no puede permitirse el lujo de asignar suficiente memoria, un bad_alloc lanzará una excepción. Pero antes de lanzar una excepción, de hecho, el sistema le llamará para configurar la función new_handler, que es una forma de la plataforma C ++ ofrecen los programadores.

typedef void(*new_handler);
new_handler set_new_handler(new_handler p)  throw();

Excelente nuevo manejador debe hacer dos cosas:

  • Disponer de más memoria
  • Llame a abortar o salida para abortar la operación, el final del programa.

std :: asignador

std :: modo de funcionamiento asignador

asignador 16 mantiene listas free_list [16], cada cadena mantiene un banco de memoria de tamaño fijo de free_list [0] byte de mantenimiento 8, cada cadena de un mantenimiento multi-lista de 8 bytes. Cuando una aplicación quiere asignar un tamaño de memoria se ajustará hacia arriba a un número entero de 8, y luego dispensada de la lista.

cada tamaño asigna asignador de memoria * 20 * 2 + RoundUp ( ) , la mitad delantera de la lista al bloque 20, la agrupación de memoria trasero llamado pool de repuesto, es más dispensando parte a la siguiente distribución del tiempo de espera y el uso, desde la piscina reducir el número de fuera de control por siempre entre 1-20. RoundUp junto con el aumento de las rondas, cada uno de la pluralidad de memoria asignada, se calculan las aplicaciones acumulativos >> 4 , y después se transfirió a un múltiplo de ocho.

proceso de dispensación se explica a modo de ejemplo: Supongamos que la memoria del sistema 10 000

  • La asignación de 32 bytes, este caso free_list [3] está vacía y la piscina está vacío, que asignará 32 * 20 * 2 + RoundUp (0 >> 4) malloc byte por uno. Luego corte del primer bloque para el cliente, los bloques restantes 19 para colgar free_list [3] en. * 2 está detrás de la operación para el tamaño de la piscina.
    • la acumulación de aplicaciones: 1280, tamaño de la piscina: 640
  • La asignación de 64 bytes, este caso free_list [7] pero hay piscina está vacía, se le asigna directamente a ella en la piscina, el primer corte a un cliente, colgando los 9 restantes a free_list [7] sucesivamente.
    • la acumulación de aplicaciones: 1280, tamaño de la piscina: 0
  • La asignación de 96 bytes, entonces el primer proceso repetido, antes de dispensar 96 * 20 * 2 + RoundUp (1280 >> 4) bytes y 20 vienen a free_list [11] el uso.
    • la acumulación de aplicaciones: 5200, tamaño de la piscina: 2000
  • La asignación de 88 bytes, este caso free_list [10] pero hay piscina está vacía, se le asigna de la piscina, porque el número de bloques asignados de la piscina cada tiempo entre 1 y 20, 20 se asigna a la misma.
    • la acumulación de aplicaciones: 5200, tamaño de la piscina: 240
  • Aplicación tres consecutivos 88 bytes porque free_list [10] 19 también es libre, asignar de modo directamente al cliente 3
    • la acumulación de aplicaciones: 5200, tamaño de la piscina: 240
  • De aplicación 8 bytes, entonces free_list [0] existe pero es piscina vacía, así que 8 bytes asignados 20 directamente desde la piscina a free_list [0] utilizando
    • la acumulación de aplicaciones: 5200, tamaño de la piscina: 80
  • Aplicación 104 bytes, entonces free_list [12] no son suficientes vacío pero una piscina, entonces la piscina 80 asignado a free_list [9], la distribución por malloc 104 * 20 * 2 + RoundUp (5200 >> 4) bytes
    • la acumulación de aplicaciones: 9688, tamaño de la piscina: 2408
  • Aplicación 112 bytes, entonces free_list [13] Sin embargo, la presencia de la piscina está vacío, se dispensa directamente desde la piscina 20 vinculado a la free_list bloque [13] en
    • la acumulación de aplicaciones: 9688, tamaño de la piscina: 168
  • Aplicación 48 bytes, este caso free_list [5] Sin embargo, la presencia de la piscina está vacío, es dispensado directamente desde el colgante piscina 3 a free_list [5] en
    • la acumulación de aplicaciones: 9688, tamaño de la piscina: 24
  • Aplicación de 72 bytes, entonces free_list [8] no está vacío pero asignado una piscina, entonces los primeros 24 bytes de la piscina vinculados a free_list [2], y luego otra vez por la asignación malloc. En este caso, el sistema ha aparentemente no está completado la asignación de memoria extra, el sistema asignará los recursos asignados dentro de una 72 más cerca de los clientes, es decir en este momento se le asignará un bloques de 80 bytes de free_list [9] y 8 + cortado en dos porciones 72, la primera parte asignada al cliente, la segunda porción en la piscina.
    • la acumulación de aplicaciones: 9688, tamaño de la piscina: 8
  • Aplicación 120 bytes, entonces free_list [14] no son lo suficientemente vacío pero como una piscina, a continuación, los primeros 8 bytes de la piscina para colgar free_list [0], el caso es, evidentemente, todavía no uso de la memoria malloc, pero free_list [14] y free_list [15] están vacías, a continuación, la forma en que se asigna.
    • la acumulación de aplicaciones: 9688, tamaño de la piscina: 0

La segunda configuración etapa código fuente asignador

enum {__ALIGN = 8};							// 小区块的上调边界
enum {__MAX_BYTES = 128};					// 小区块的上限
enum {__NFREELISTS = __MAX_BYTES/__ALIGN};	// free-list 的个数

class alloc {
private:
	union obj{
		union obj* free_list_link;
	};
	static char* start_free;				// 指向 pool 的头
	static char* end_free;					// 指向 pool 的尾
	static size_t heap_size;				// 累计分配量
	static obj* free_list[__NFREELISTS];	// free_list 数组

	static size_t ROUND_UP(size_t bytes) {	// 将 bytes 向上调整到 8 的倍数
		return ((bytes + __ALIGN-1)) & ~(__ALIGN-1);
	}
	static size_t FREELIST_INDEX(size_t bytes) {	// 获得应该从哪个 free_list 分配内存
		return (bytes+__ALIGN-1)/__ALIGN -1;
	} 
	static void* refill(size_t n) {			// 为链表填充内存,此时的 n 已经是 8 的倍数
		int nobjs = 20;
		char *chunk = chunk_alloc(n, nobjs);
		obj **my_free_list;
		obj *result;
		obj *current_obj;
		obj *next_obj;
		if(1 == nobjs)	return chunk;
		my_free_list = free_list + FREELIST_INDEX(n);
		result = (obj*)chunk;
		*my_free_list = next_obj = (obj*)(chunk+n);		// 直接拿第二块挂到链表上
		for(int i=1; ; i++) {
			current_obj = next_obj;
			next_obj = (obj*)((char*)next_obj+n);
			if(nobjs-1 == i) {
				current_obj->free_list_link = NULL;
				break;
			} else {
				current_obj->free_list_link = next_obj;
			}
		}
		return result;
	}
	static char* chunk_alloc(size_t size, int &nobjs){	// 分配一大块内存
		char *result;
		size_t total_bytes = size*nobjs;
		size_t bytes_left = end_free - start_free;
		if(bytes_left >= total_bytes) {		// 先从 pool 池分配,如果能够满足分配 20 个块
			result = start_free;
			start_free += total_bytes;
			return result;
		} else if(bytes_left >= size) {		// 如果不够 20 个但至少能分配一个
			nobjs = bytes_left/size;
			total_bytes = size*nobjs;
			result = start_free;
			start_free += total_bytes;
			return result;
		} else {							// pool 池不够用
			size_t bytes_to_get = 2*total_bytes+ROUND_UP(heap_size>>4);
			if(bytes_left > 0) {			// 处理 pool 池碎片
				obj **my_free_list = free_list + FREELIST_INDEX(bytes_left);
				((obj*)start_free)->free_list_link = *my_free_list;
				*my_free_list = (obj*)start_free;
			}
			start_free = (char*)malloc(bytes_to_get);	// 先分配到 pool 池中
			if(0 == start_free) {			// 如果系统内存不够分配
				obj **my_free_list;
				obj *p;
				for(int i=size; i<=__MAX_BYTES; i += __ALIGN) {	// 往后找一块可以拿来用的内存
					my_free_list = free_list + FREELIST_INDEX(i);
					p = *my_free_list;
					if(0 != p) {			// 如果找到一块可以用的
						*my_free_list = p->free_list_link;
						start_free = (char*)p;
						end_free = start_free+i;
						return chunk_alloc(size, nobjs);// 扩充的 pool,所以在分配一次一定可以分配到
					}
				}
				// 尝试利用一级配置器分配内存
				end_free = 0;
//				start_free = (char*)malloc_alloc::allocate(bytes_to_get);
			}
			heap_size += bytes_to_get;
			end_free = start_free + bytes_to_get;
			return chunk_alloc(size, nobjs);			// 扩充的 pool,所以在分配一次一定可以分配到
		}
	}
	
public:
	static void* allocate(size_t n) {
		obj **my_free_list;					// obj**
		obj *result;
		if(n > (size_t)__MAX_BYTES) {		// 改用第一级p配置器
//			return malloc_alloc::allocate(n);
		}
		my_free_list = free_list + FREELIST_INDEX(n);
		result = *my_free_list;				// 获得对应的链表指针
		if(result == NULL) {				// 如果链表为空
			void *r = refill(ROUND_UP(n));
			return r;
		}
		*my_free_list = result->free_list_link;
		return result;
	}
	static void deallocate(void *p, size_t n) {
		obj *q = (obj*) p;
		obj **my_free_list;					// obj**
		if(n > (size_t)__MAX_BYTES) {		// 改用第一级p配置器
//			malloc_alloc::deallocate(p, n);
			return ;
		}
		my_free_list = free_list + FREELIST_INDEX(n);
		q->free_list_link = *my_free_list;
		*my_free_list = q;
	}
};
char* alloc::start_free = NULL;
char* alloc::end_free = NULL;
size_t alloc::heap_size = 0;
alloc::obj* alloc::free_list[__NFREELISTS] = {0};

Supongo que te gusta

Origin www.cnblogs.com/Jiaaaaaaaqi/p/12629901.html
Recomendado
Clasificación