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