009zk安装及kafka和zk dashboard管
981 2023-04-03 04:27:16
阅读目录
在上一篇 C++内存管理:new / delete 和 cookie 中谈到,频繁的调用 malloc 会影响运行效率以及产生额外的 cookie, 而内存池的思想是预先申请一大块内存,当有内存申请需求时,从内存池中取出一块内存分配给目标对象。
它的实现过程为:
回到顶部
?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
#include <iostream>
using
namespace
std;
class
Screen {
public
:
Screen(
int
x) : i(x) { };
int
get() {
return
i; }
void
* operator
new
(
size_t
);
void
operator
delete
(
void
*,
size_t
);
private
:
Screen* next;
static
Screen* freeStore;
//头指针
static
const
int
screenChunk;
//内存块数量
private
:
int
i;
};
Screen* Screen::freeStore = 0;
const
int
Screen::screenChunk = 5;
void
* Screen::operator
new
(
size_t
size){
Screen *p;
if
(!freeStore) {
//内存池是空的
size_t
chunk = screenChunk * size;
freeStore = p =
reinterpret_cast
<Screen*>(
new
char
[chunk]);
for
(; p != &freeStore[screenChunk - 1]; ++p) {
//以链表的形式串联起来
p->next = p + 1;
}
p->next = 0;
}
p = freeStore;
freeStore = freeStore->next;
return
p;
}
void
Screen::operator
delete
(
void
*p,
size_t
){
//将内存块重新加入链表表头,同时调整头指针
(
static_cast
<Screen*>(p))->next = freeStore;
freeStore =
static_cast
<Screen*>(p);
}
//-------------
void
test(){
cout <<
"Size: "
<<
sizeof
(Screen) << endl;
size_t
const
N = 100;
Screen* p[N];
for
(
int
i = 0; i < N; ++i)
p[i] =
new
Screen(i);
for
(
int
i = 0; i < 10; ++i)
//输出地址观察
cout << i <<
": "
<< p[i] << endl;
for
(
int
i = 0; i < N; ++i)
delete
p[i];
}
int
main(){
test();
return
0;
}
在上面的代码中设置一个内存池为5个内存块,当我们进行100次内存申请后,打印出前10个地址查看,可以看到前5个地址是连续的,后5个也是连续的,但中间由于重新申请了内存池,所以不是连续的。
但是这样的方法还存在着问题,那就是引入了额外的指针内存消耗,接下来将使用embedded pointer进行改进。
回到顶部
上面就使用到了嵌入指针,一个 AirplaneRep 对象的大小为 8 字节,而一个 Airplane 的指针大小为 4 字节或 8 字节。在 32 位机器下, 指针可以借用 AirplaneRep 对象所占的 8 字节内存空间中的前 4 个字节,用来连接空闲的内存块。而当内存块需要被分配给对象时,此时它已从链表中移除,也就不需要指针来连接了。此时的 8 字节内存空间由 AirplaneRep 占据。当内存释放时也是同理,由于 Rep 和 next 不会同时用到,所以 embedded pointer 的做法可以减少内存消耗。
回到顶部
前面的实现需要为每个类都重写 operator new 和 operator delete,由于内容是一样的,使用另一个类来完成这些重复的操作。
如此一来,我们的 class 只需要去调用 allocator 即可完成内存的申请和释放工作。
?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132#include <iostream>
#include <complex>
using
namespace
std;
namespace
jj09{
class
allocator{
private
:
struct
obj {
struct
obj* next;
//embedded pointer
};
public
:
void
* allocate(
size_t
);
void
deallocate(
void
*,
size_t
);
void
check();
private
:
obj* freeStore =
nullptr
;
const
int
CHUNK = 5;
};
void
* allocator::allocate(
size_t
size){
obj* p;
if
(!freeStore) {
size_t
chunk = CHUNK * size;
freeStore = p = (obj*)
malloc
(chunk);
for
(
int
i = 0; i < (CHUNK - 1); ++i) {
p->next = (obj*)((
char
*)p + size);
p = p->next;
}
p->next =
nullptr
;
//last
}
p = freeStore;
freeStore = freeStore->next;
return
p;
}
void
allocator::deallocate(
void
* p,
size_t
){
((obj*)p)->next = freeStore;
freeStore = (obj*)p;
}
void
allocator::check(){
obj* p = freeStore;
int
count = 0;
while
(p) {
cout << p << endl;
p = p->next;
count++;
}
cout << count << endl;
}
//--------------
class
Foo {
public
:
long
L;
string str;
static
allocator myAlloc;
public
:
Foo(
long
l) : L(l) { }
static
void
* operator
new
(
size_t
size){
return
myAlloc.allocate(size);
}
static
void
operator
delete
(
void
* pdead,
size_t
size){
return
myAlloc.deallocate(pdead, size);
}
};
allocator Foo::myAlloc;
class
Goo {
public
:
complex<
double
> c;
string str;
static
allocator myAlloc;
public
:
Goo(
const
complex<
double
>& x) : c(x) { }
static
void
* operator
new
(
size_t
size){
return
myAlloc.allocate(size);
}
static
void
operator
delete
(
void
* pdead,
size_t
size){
return
myAlloc.deallocate(pdead, size);
}
};
allocator Goo::myAlloc;
//-------------
void
test_static_allocator_3(){
Foo* p[100];
cout <<
"sizeof(Foo)= "
<<
sizeof
(Foo) << endl;
for
(
int
i = 0; i < 23; ++i) {
//23,任意数, 随意看看结果
p[i] =
new
Foo(i);
cout << p[i] <<
' '
<< p[i]->L << endl;
}
//Foo::myAlloc.check();
for
(
int
i = 0; i < 23; ++i) {
delete
p[i];
}
//Foo::myAlloc.check();
{
Goo* p[100];
cout <<
"sizeof(Goo)= "
<<
sizeof
(Goo) << endl;
for
(
int
i = 0; i < 17; ++i) {
//17,任意数, 随意看看结果
p[i] =
new
Goo(complex<
double
>(i, i));
cout << p[i] <<
' '
<< p[i]->c << endl;
}
//Goo::myAlloc.check();
for
(
int
i = 0; i < 17; ++i) {
delete
p[i];
}
//Goo::myAlloc.check();
}
}
}
//namespace
int
main(
void
)
{
jj09::test_static_allocator_3();
return
0;
}
回到顶部
在上面的 Foo 和 Goo 中,每次还要写一大堆重复的内容,于是可以使用宏进一步简化:
参考:
【C++内存管理】内存管理实例 (二) —— Embeded pointer
嵌入式指针embedded pointer的概念以及用法
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。