前言
正文
一, C++中的对象new的流程
在C++中 new是调用::operator new (); //分配内存的
在调用赋值函数 construct();
释放的流程
destroy() ::operator delete ; //释放内存
//初始化对象的值
template <class T1, class T2>
inline void construct(T1*p, const T2& value)
{
new (p) T1(value); // inivke construct
}
//调用析构函数
template <class T>
inline void destroy(T* pointer)
{
pointer->~T(); // inivke destroy();
}
template <int inst>
class cnew_alloc {
public:
// this one is needed for proper simple_alloc wrapping
typedef char value_type;
//分配内存
static void* allocate(size_t n)
{
return 0 == n ? 0 : ::operator new(n);
}
static void* reallocate(void *p, size_t old_sz, size_t new_sz)
{
void* result = allocate(new_sz);
size_t copy_sz = new_sz > old_sz? old_sz : new_sz;
memcpy(result, p, copy_sz);
deallocate(p, old_sz);
return result;
}
//释放内存
static void deallocate(void* p)
{
::operator delete(p);
}
static void deallocate(void* p, size_t)
{
::operator delete(p);
}
};
其实new 实际也是调用malloc 函数
二, STL中分配内存alloc
STL中有一级分配内存和二级分配内存
一级分配内存就是使用malloc分配内存的 当前申请的内存大于128个字节时就是使用malloc分配内存,当小于128个字节时就使用内存池,
1,一级内存就是简单对malloc进行封装
/***********************************************************************************************
created: 2020-06-24
author: chensong
purpose: cmalloc_alloc.h
我可能会遇到很多的人,听他们讲好2多的故事,我来写成故事或编成歌,用我学来的各种乐器演奏它。
然后还可能在一个国家遇到一个心仪我的姑娘,她可能会被我帅气的外表捕获,又会被我深邃的内涵吸引,在某个下雨的夜晚,她会全身淋透然后要在我狭小的住处换身上的湿衣服。
3小时候后她告诉我她其实是这个国家的公主,她愿意向父皇求婚。我不得已告诉她我是穿越而来的男主角,我始终要回到自己的世界。
然后我的身影慢慢消失,我看到她眼里的泪水,心里却没有任何痛苦,我才知道,原来我的心被丢掉了,我游历全世界的原因,就是要找回自己的本心。
于是我开始有意寻找各种各样失去心的人,我变成一块砖头,一颗树,一滴水,一朵白云,去听大家为什么会失去自己的本心。
我发现,刚出生的宝宝,本心还在,慢慢的,他们的本心就会消失,收到了各种黑暗之光的侵蚀。
从一次争论,到嫉妒和悲愤,还有委屈和痛苦,我看到一只只无形的手,把他们的本心扯碎,蒙蔽,偷走,再也回不到主人都身边。
我叫他本心猎手。他可能是和宇宙同在的级别 但是我并不害怕,我仔细回忆自己平淡的一生 寻找本心猎手的痕迹。
沿着自己的回忆,一个个的场景忽闪而过,最后发现,我的本心,在我写代码的时候,会回来。
安静,淡然,代码就是我的一切,写代码就是我本心回归的最好方式,我还没找到本心猎手,但我相信,顺着这个线索,我一定能顺藤摸瓜,把他揪出来。
************************************************************************************************/
//
#ifndef _CMALLOC_ALLOC_H_
#define _CMALLOC_ALLOC_H_
#include <cstdlib>
#include <cstdio>
namespace chen
{
typedef void (* coom_handler_type)();
template <int inst>
class cmalloc_alloc
{
private:
static void *oom_malloc(size_t);
static void *oom_realloc(void *, size_t);
static coom_handler_type oom_handler;
public:
// this one is needed for proper simple_alloc wrapping
typedef char value_type;
static void * allocate(size_t n)
{
printf("alloc size = %llu\n", n);
void *result = ::malloc(n);
if (0 == result) result = oom_malloc(n);
return result;
}
static void deallocate(void *p, size_t n /* n */)
{
printf("free size = %llu\n", n);
::free((char*)p);
}
static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
void * result = ::realloc((char*)p, new_sz);
if (0 == result) result = oom_realloc(p, new_sz);
return result;
}
static coom_handler_type set_malloc_handler(coom_handler_type f)
{
coom_handler_type old = oom_handler;
oom_handler = f;
return(old);
}
};
template <int inst>
coom_handler_type cmalloc_alloc<inst>::oom_handler=(coom_handler_type)0 ;
template <int inst>
void * cmalloc_alloc<inst>::oom_malloc(size_t n)
{
coom_handler_type my_malloc_handler;
void *result;
for (;;)
{
my_malloc_handler = oom_handler;
if (0 == my_malloc_handler)
{
fprintf(stderr,"out of memory");
exit(1);
}
(*my_malloc_handler)();
result = malloc(n);
if (result)
{
return(result);
}
}
}
template <int inst>
void * cmalloc_alloc<inst>::oom_realloc(void *p, size_t n)
{
coom_handler_type my_malloc_handler;
void *result;
for (;;)
{
my_malloc_handler = oom_handler;
if (0 == my_malloc_handler)
{
fprintf(stderr,"out of memory");
exit(1);
}
(*my_malloc_handler)();
result = ::realloc((char*)p, n);
if (result)
{
return(result);
}
}
}
typedef cmalloc_alloc<0 > malloc_alloc;
} // namespace chen
#endif //_CMALLOC_ALLOC_H_
2, 二级分配使用内存池技术
在内存池中维护16个内存块链表和还有被内存块使用备用内存
16数组中的内存块分别是 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128 都是8倍数 内存对齐
中使用 &~ 运算符 是对需要内存进行内存调整到 8的倍数
例子:
31 ===> 32 //调整后是
0001 0111 ===> (0001 0111 + 0111) & ~(0111) ===> 0010 0000 == 32
公式
static size_t round_up(size_t bytes)
{
return (bytes + (7)) &~(7);
}
16个数组是维持16种内存块的链表
但是它分配内存块40k内存节点分配20个 是 800k是给数组中 中下标4中链表管理19个节点40k的内存 , 但是实际内存内存大于800k而是申请的1600k 还有的800k留给内存池管理了 // 当你在申请内存 32k的实际就会到内存池中拿出640k出现给数组下标3管理管理,这个就是STL的设置内存池精妙之处
/***********************************************************************************************
created: 2020-06-23
author: chensong
purpose: calloc_mem_pool
我可能会遇到很多的人,听他们讲好2多的故事,我来写成故事或编成歌,用我学来的各种乐器演奏它。
然后还可能在一个国家遇到一个心仪我的姑娘,她可能会被我帅气的外表捕获,又会被我深邃的内涵吸引,在某个下雨的夜晚,她会全身淋透然后要在我狭小的住处换身上的湿衣服。
3小时候后她告诉我她其实是这个国家的公主,她愿意向父皇求婚。我不得已告诉她我是穿越而来的男主角,我始终要回到自己的世界。
然后我的身影慢慢消失,我看到她眼里的泪水,心里却没有任何痛苦,我才知道,原来我的心被丢掉了,我游历全世界的原因,就是要找回自己的本心。
于是我开始有意寻找各种各样失去心的人,我变成一块砖头,一颗树,一滴水,一朵白云,去听大家为什么会失去自己的本心。
我发现,刚出生的宝宝,本心还在,慢慢的,他们的本心就会消失,收到了各种黑暗之光的侵蚀。
从一次争论,到嫉妒和悲愤,还有委屈和痛苦,我看到一只只无形的手,把他们的本心扯碎,蒙蔽,偷走,再也回不到主人都身边。
我叫他本心猎手。他可能是和宇宙同在的级别 但是我并不害怕,我仔细回忆自己平淡的一生 寻找本心猎手的痕迹。
沿着自己的回忆,一个个的场景忽闪而过,最后发现,我的本心,在我写代码的时候,会回来。
安静,淡然,代码就是我的一切,写代码就是我本心回归的最好方式,我还没找到本心猎手,但我相信,顺着这个线索,我一定能顺藤摸瓜,把他揪出来。
************************************************************************************************/
#ifndef CSTL_SOURCE_CALLOC_MEM_POOL_H
#define CSTL_SOURCE_CALLOC_MEM_POOL_H
#include "cmalloc_alloc.h"
#include <mutex>
namespace chen {
union cnode_alloc_obj;
union cnode_alloc_obj
{
union cnode_alloc_obj* free_list_link;
char client_data[1]; // info address
};
template <bool trheads, int inst>
class calloc
{
public:
// this one is needed for proper simple_alloc wrapping
typedef char value_type;
typedef cnode_alloc_obj obj;
public:
//内存对齐最小字节
enum {__ALIGN = 8};
// 内存池中最大内存节点 128
enum {__MAX_BYTES = 128};
// 内存
enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
private:
// 内存字节对齐 8的倍数
static size_t round_up(size_t bytes)
{
return ((bytes + __ALIGN -1) & ~(__ALIGN -1));
}
// 内存字节数组的下标
static size_t free_list_index(size_t bytes)
{
return ((bytes + __ALIGN -1)/__ALIGN -1);//
}
//
static void *refill(size_t n);
static char * chunk_alloc(size_t size, int & nobjes);
// Chunk allocation state.
static char *start_free;
static char *end_free;
static size_t heap_size;
public:
/* n must be > 0 */
static void * allocate(size_t n);
/* p may not be 0 */
static void deallocate(void *p, size_t n);
static void * reallocate(void *p, size_t old_sz, size_t new_sz);
static void show_info()
{
printf("mem_pool node size = %llu\n", (size_t)(end_free - start_free));
printf("mem_pool use size = %llu\n", m_use_size);
printf("mem_pool size = %llu\n", heap_size);
}
private :
static obj * free_list[__NFREELISTS];
static std::mutex m_lock;
static size_t m_use_size;
};
typedef calloc<false, 0 > csingle_client_alloc;
typedef calloc<true, 0 > cmultithreaded_alloc;
template <bool threads, int inst>
inline void * calloc<threads,inst>::allocate(size_t n)
{
obj ** my_free_list;
obj * result;
m_use_size +=n;
if (n > (size_t)__MAX_BYTES)
{
return(malloc_alloc::allocate(n));
}
printf("allocate index = %llu\n", free_list_index(n));
my_free_list = free_list + free_list_index(n);
// Acquire the lock here with a constructor call.
// This ensures that it is released in exit or during stack
// unwinding.
/*REFERENCED*/
if (threads)
{
m_lock.lock();
}
result = *my_free_list;
if (result == 0)
{
void *r = refill(round_up(n));
return r;
}
*my_free_list = result -> free_list_link;
if (threads)
{
m_lock.unlock();
}
return (result);
}
template <bool threads, int inst>
inline void calloc<threads, inst>::deallocate(void *p, size_t n)
{
obj *q = (obj *)p;
obj ** my_free_list;
m_use_size -=n;
if (n > (size_t)__MAX_BYTES)
{
malloc_alloc::deallocate(p, n);
return;
}
printf("deallocate index = %llu\n", free_list_index(n));
my_free_list = free_list + free_list_index(n);
// acquire lock
if (threads)
{
m_lock.lock();
}
q->free_list_link = *my_free_list;
*my_free_list = q;
// lock is released here
if (threads)
{
m_lock.unlock();
}
}
/* We allocate memory in large chunks in order to avoid fragmenting */
/* the malloc heap too much. */
/* We assume that size is properly aligned. */
/* We hold the allocation lock. */
template <bool threads, int inst>
char* calloc<threads, inst>::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)
{
result = start_free;
start_free += total_bytes;
return(result);
}
else if (bytes_left >= size)
{
nobjs = bytes_left/size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return(result);
}
else
{
// 这边 heap_size >> 4 ====> 扩容作准备的 内存池
size_t bytes_to_get = 2 * total_bytes + round_up(heap_size >> 4);
// Try to make use of the left-over piece.
if (bytes_left > 0)
{
obj ** my_free_list = free_list + free_list_index(bytes_left);
((obj *)start_free) -> free_list_link = *my_free_list;
*my_free_list = (obj *)start_free;
}
start_free = (char *)malloc_alloc::allocate(bytes_to_get);
if (0 == start_free)
{
int i;
obj ** my_free_list;
obj *p;
// Try to make do with what we have. That can't
// hurt. We do not try smaller requests, since that tends
// to result in disaster on multi-process machines.
for (i = size; i <= __MAX_BYTES; i += __ALIGN)
{
my_free_list = free_list + free_list_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));
// Any leftover piece will eventually make it to the
// right free list.
}
}
end_free = 0; // In case of exception.
start_free = (char *)malloc_alloc::allocate(bytes_to_get);
// This should either throw an
// exception or remedy the situation. Thus we assume it
// succeeded.
}
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return(chunk_alloc(size, nobjs));
}
}
/* Returns an object of size n, and optionally adds to size n free list.*/
/* We assume that n is properly aligned. */
/* We hold the allocation lock. */
template <bool threads, int inst>
void* calloc<threads, inst>::refill(size_t n)
{
int nobjs = 20;
char * chunk = chunk_alloc(n, nobjs);
obj * * my_free_list;
obj * result;
obj * current_obj, * next_obj;
int i;
if (1 == nobjs)
{
return(chunk);
}
my_free_list = free_list + free_list_index(n);
/* Build free list in chunk */
// node list -->>>>>> 8 * ? = 128
result = (obj *)chunk;
*my_free_list = next_obj = (obj *)(chunk + n);
for (i = 1; ; i++)
{
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if (nobjs - 1 == i)
{
current_obj -> free_list_link = 0;
break;
}
else
{
current_obj -> free_list_link = next_obj;
}
}
return(result);
}
template <bool threads, int inst>
void* calloc<threads, inst>::reallocate(void *p, size_t old_sz, size_t new_sz)
{
void * result;
size_t copy_sz;
if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES)
{
return(malloc_alloc::reallocate(p, old_sz, new_sz));
}
if (round_up(old_sz) == round_up(new_sz))
{
return(p);
}
result = allocate(new_sz);
copy_sz = new_sz > old_sz? old_sz : new_sz;
::memcpy(result, p, copy_sz);
deallocate(p, old_sz);
return(result);
}
template <bool threads, int inst>
char *calloc<threads, inst>::start_free = 0;
template <bool threads, int inst>
char *calloc<threads, inst>::end_free = 0;
template <bool threads, int inst>
size_t calloc<threads, inst>::heap_size = 0;
template <bool threads, int inst>
size_t calloc<threads, inst>::m_use_size = 0;
template <bool threads, int inst>
cnode_alloc_obj * calloc<threads, inst>::free_list[__NFREELISTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
}
#endif //CSTL_SOURCE_CALLOC_MEM_POOL_H