tecnologia de gerenciamento de memória C ++

C ++ primitivas membery

alocação lançamento categoria pode sobrecarregar
malloc livre C função não pode
Novo excluir expressões C ++ não pode
:: novo operador :: operator delete função C ++ lata
alocador <T> :: alocar alocador <T> :: deallocate Biblioteca Padrão C ++ Pode ser projetado livremente para combinar com qualquer recipiente
  • O quarto método tem diferentes maneiras em diferentes versões do 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

expressão novo / delete

nova irá alocar a memória, e, em seguida, chamar o construtor, a realização de modo concreto de novas segue, mas geralmente sobrecarregado novo, estão sobrecarregados :: operator new

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

série nova / delete

Ao abrir-se uma nova matriz irá atribuir uma matriz de 4 bytes no cookie posição de partida, um cookie que regista o comprimento da matriz de distribuição. Se você usar a versão de exclusão só irá liberar um deles, o outro vazamento de memória bloco ocorre ao usar liberação de exclusão [], você pode aplicar para garantir que a memória está completamente liberado.

Processo para a construção de matrizes e eliminado, de acordo com a sequência de padrão chamando um construtor 0,1,2, 2,1,0 prima tabela chamar sequencialmente o processo de destruição.

colocação de novo

colocação de novo nos permite construir um objeto em uma memória já alocada

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) {
}

classe alocar

malloc havia quatro bytes de cookie de alocação de memória na ponta a ponta, o tamanho da gravação da memória alocada. Portanto, a memória malloc frequente fará com que uma grande parte dos resíduos.

solução técnica desta abordagem é através da técnica de pool de memória, um grande I descartável pode atribuir memória para alocar memória no processo posterior, uma parte do dispensado para uso da maior parte do programa.

  • A primeira edição das técnicas de gerenciamento de memória são as seguintes
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;
}
  • A segunda versão é semelhante à primeira versão, mas acrescentou a otimização união.
  • As duas primeiras versões das operações de alocação de memória são implementados dentro do objeto, mas de gravação para cada objeto uma alocação de memória não é claramente realista, a terceira versão do processo de alocação de memória está a ser extraído, encapsulada em uma única classe alocar neste alocar memória contém para cada classe, e em seguida, chama a função de alocar o processo de distribuição é concluída.

novo manipulador

Quando o novo operador não pode dar ao luxo de alocar memória suficiente, uma bad_alloc irá lançar uma exceção. Mas antes de lançar uma exceção, na verdade, o sistema vai chamá-lo para configurar função new_handler, que é uma maneira de plataforma C ++ programadores oferecer.

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

Excelente novo manipulador deve fazer duas coisas:

  • Disponibilizar mais memória
  • Chamada abort ou saída para abortar a operação, as extremidades do programa.

std :: allocator

std :: modo de operação alocador

alocador 16 mantém listas free_list [16], cada cadeia mantém um conjunto de memória de tamanho fixo de free_list [0] byte manutenção 8, cada cadeia de uma manutenção multi-lista de 8 bytes. Quando uma aplicação deseja atribuir um tamanho de memória irá ser ajustada para cima para um número inteiro de 8, e, em seguida, distribua a partir da lista.

cada tamanho aloca alocador de memória * 20 * 2 + RoundUp ( ) , a metade da frente da lista para bloquear 20, o pool de memória traseira chamado piscina de reposição, é mais dispensar parte para a próxima distribuição do tempo de espera e utilizar, a partir da piscina reduzir o número de fora de controlo sempre entre 1-20. Ajuntamento, juntamente com o aumento das voltas, cada uma da pluralidade de memória alocada, são calculados aplicações cumulativas >> 4 , e, em seguida, transferida para um múltiplo de oito.

processo de distribuição é explicado a título de exemplo: suponha que a memória do sistema 10.000

  • Atribuição de 32 bytes, neste caso free_list [3] é vazio e a piscina estiver vazio, ele irá alocar 32 * 20 * 2 + ajuntamento (0 >> 4) malloc byte por um. Em seguida, corte a partir do primeiro bloco para o cliente, os blocos restantes 19 para pendurar free_list [3] diante. * 2 está por trás da operação para o tamanho da piscina.
    • aplicações cumulativas: 1280, tamanho da piscina: 640
  • Atribuição de 64 bytes, neste caso free_list [7], mas existem piscina está vazia, isto é directamente atribuído a ele pelo piscina, o primeiro corte para um cliente, pendurando o restante 9 a free_list [7] no.
    • aplicações cumulativas: 1280, tamanho da piscina: 0
  • Atribuição de 96 bytes, em seguida, utilizadas no primeiro processo, antes de dispensar 96 * 20 * 2 + ajuntamento (1280 >> 4) bytes e 20 vêm a free_list [11] utilização.
    • aplicações cumulativas: 5200, tamanho da piscina: 2000
  • Atribuição de 88 bytes, neste caso free_list [10], mas existem piscina está vazia, é atribuído a partir da piscina, porque o número de blocos alocados a partir da piscina de cada vez entre 1 e 20, 20 é atribuído a ele.
    • aplicações cumulativas: 5200, tamanho da piscina: 240
  • Aplicação três períodos consecutivos de 88 bytes porque free_list [10] 19 existe também livre, de modo directamente atribuído ao cliente 3
    • aplicações cumulativas: 5200, tamanho da piscina: 240
  • Aplicação 8 bytes, em seguida, free_list [0] existe mas é piscina vazia, de modo 8 bytes atribuídos 20 directamente a partir do conjunto de free_list [0] usando
    • aplicações cumulativas: 5200, tamanho da piscina: 80
  • Aplicação 104 bytes, em seguida, free_list [12], não são suficientes esvaziar mas uma piscina, em seguida, a piscina 80 atribuído para free_list [9], a distribuição por malloc 104 * 20 * 2 + ajuntamento (5200 >> 4) bytes
    • aplicações cumulativas: 9688, tamanho da piscina: 2408
  • Aplicação 112 bytes, em seguida, free_list [13] No entanto, a presença da piscina estiver vazio, ele é aplicado directamente a partir da piscina de 20 ligada ao free_list bloco [13] sobre
    • aplicações cumulativas: 9688, tamanho da piscina: 168
  • Aplicação de 48 bytes, neste caso free_list [5] No entanto, a presença da piscina estiver vazio, ele é aplicado directamente a partir da suspensão da piscina 3 a free_list [5] em
    • aplicações cumulativas: 9688, tamanho da piscina: 24
  • Aplicação 72 bytes, em seguida, free_list [8] não está vazia mas atribuída uma piscina, em seguida, os primeiros 24 bytes da piscina associada a free_list [2], e em seguida, novamente por alocação malloc. Neste caso, o sistema tem, aparentemente, nenhuma alocação de memória extra é concluída, o sistema irá alocar os recursos alocados dentro de um 72 mais próximo aos clientes, isto é, neste momento será atribuído em blocos de 80 bytes de free_list [9] e 8 + cortado em duas porções 72, a primeira porção atribuído ao cliente, a segunda porção em piscina.
    • aplicações cumulativas: 9688, tamanho da piscina: 8
  • Aplicação 120 bytes, então free_list [14] não são suficientes vazia, mas como uma piscina, em seguida, os primeiros 8 bytes da piscina para pendurar free_list [0], o caso é, obviamente, ainda não o uso de memória malloc, mas free_list [14] e free_list [15] estiverem vazias, o modo como é alocado.
    • aplicações cumulativas: 9688, tamanho da piscina: 0

A segunda configuração fase alocador código fonte

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};

Acho que você gosta

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