>
GNU TeXmacs GNU TeXmacs 440成员

学习笔记: TeXmacs 中内存池的实现 (fast_alloc)

babysoul 2017-08-03
每次利用 malloc/free 或 new/delete 进行内存申请与释放时, 都会涉及内核空间与用户空间的频繁切换, 系统也会疲于找寻合适大小的存储空间, 导致存储碎片化, 性能显著降低.

TeXmacs 仅在启动时就会进行百万次的内存申请/释放操作, 这些操作所涉及的内存规模, 其实往往并不大. 为了优化性能, 作者使用内存池技术以有效降低上述开销. 具体来说, 系统的 new 与 delete 被自定义的 tm_new 与 tm_delete 所替代 (关键代码在 src/System/Misc/fast_alloc.cpp 与 .hpp)

以下是原理及流程:



可以独立运行的测试代码:

#include <cstdlib>
#include <cstdio>
#include <new>

#define BLOCK_SIZE 65536
#define WORD_LENGTH 8
#define WORD_LENGTH_INC 7
#define WORD_MASK 0xfffffffffffffff8
#define MAX_FAST 264

char alloc_table[MAX_FAST];
char* alloc_mem = NULL;
size_t alloc_remains = 0;
int fast_chunks = 0;
int large_uses = 0;

#define alloc_ptr(i) (*((void**) (alloc_table+i)))
#define ind(ptr) (*((void**) ptr))

void*
safe_malloc (register size_t sz) {
void* ptr = malloc(sz);
if (ptr == NULL) { printf("Fatal error: out of memor...< sz) {
alloc_mem = (char*)safe_malloc(BLOCK_SIZE);
alloc_remains = BLOCK_SIZE;
fast_chunks ++;
}
register void* ptr = alloc_mem;
alloc_mem += sz;
alloc_remains -= sz;
return ptr;
}

void*
fast_new (register size_t s) {
register void* ptr;
s = (s + WORD_LENGTH + WORD_LENGTH_INC) & WORD_MASK;
if (s < MAX_FAST) {
ptr = alloc_ptr(s);
if (ptr == NULL) ptr = enlarge_malloc(s);
else alloc_ptr(s) = ind(ptr);
} else {
printf("Large allocation of %d bytes\n", s);
ptr = safe_malloc(s);
large_uses += s;
}
*((size_t *) ptr) = s;
return (void*) (((char*)ptr) + WORD_LENGTH);
}

void
fast_delete (register void* ptr) {
ptr = (void*) (((char*)ptr) - WORD_LENGTH);
register size_t s = *((size_t*)ptr); // get the size allocated
if (s < MAX_FAST) {
ind(ptr) = alloc_ptr(s);
alloc_ptr(s) = ptr;
} else {
printf("Large free of %d bytes\n", s);
free(ptr);
large_uses -= s;
}
}

template<typename C><typename C, typename A1><typename C, typename A1, typename A2><typename C> inline void
tm_delete (C* ptr) {
ptr-><char><Complex><char><char>
每次利用 malloc/free 或 new/delete 进行内存申请与释放时, 都会涉及内核空间与用户空间的频繁切换, 系统也会疲于找寻合适大小的存储空间, 导致存储碎片化, 性能显著降低.

TeXmacs 仅在启动时就会进行百万次的内存申请/释放操作, 这些操作所涉及的内存规模, 其实往往并不大. 为了优化性能, 作者使用内存池技术以有效降低上述开销. 具体来说, 系统的 new 与 delete 被自定义的 tm_new 与 tm_delete 所替代 (关键代码在 src/System/Misc/fast_alloc.cpp 与 .hpp)

以下是原理及流程:



可以独立运行的测试代码:

#include <cstdlib>
#include <cstdio>
#include <new>

#define BLOCK_SIZE 65536
#define WORD_LENGTH 8
#define WORD_LENGTH_INC 7
#define WORD_MASK 0xfffffffffffffff8
#define MAX_FAST 264

char alloc_table[MAX_FAST];
char* alloc_mem = NULL;
size_t alloc_remains = 0;
int fast_chunks = 0;
int large_uses = 0;

#define alloc_ptr(i) (*((void**) (alloc_table+i)))
#define ind(ptr) (*((void**) ptr))

void*
safe_malloc (register size_t sz) {
void* ptr = malloc(sz);
if (ptr == NULL) { printf("Fatal error: out of memory\n"); abort(); }
return ptr;
}

void*
enlarge_malloc (register size_t sz) {
if (alloc_remains < sz) {
alloc_mem = (char*)safe_malloc(BLOCK_SIZE);
alloc_remains = BLOCK_SIZE;
fast_chunks ++;
}
register void* ptr = alloc_mem;
alloc_mem += sz;
alloc_remains -= sz;
return ptr;
}

void*
fast_new (register size_t s) {
register void* ptr;
s = (s + WORD_LENGTH + WORD_LENGTH_INC) & WORD_MASK;
if (s < MAX_FAST) {
ptr = alloc_ptr(s);
if (ptr == NULL) ptr = enlarge_malloc(s);
else alloc_ptr(s) = ind(ptr);
} else {
printf("Large allocation of %d bytes\n", s);
ptr = safe_malloc(s);
large_uses += s;
}
*((size_t *) ptr) = s;
return (void*) (((char*)ptr) + WORD_LENGTH);
}

void
fast_delete (register void* ptr) {
ptr = (void*) (((char*)ptr) - WORD_LENGTH);
register size_t s = *((size_t*)ptr); // get the size allocated
if (s < MAX_FAST) {
ind(ptr) = alloc_ptr(s);
alloc_ptr(s) = ptr;
} else {
printf("Large free of %d bytes\n", s);
free(ptr);
large_uses -= s;
}
}

template<typename C> inline C*
tm_new () {
void* ptr= fast_new (sizeof (C));
(void) new (ptr) C ();
return (C*) ptr;
}

template<typename C, typename A1> inline C*
tm_new (const A1& a1) {
void* ptr = fast_new (sizeof (C));
(void) new (ptr) C (a1);
return (C*) ptr;
}

template<typename C, typename A1, typename A2> inline C*
tm_new (const A1& a1, const A2& a2) {
void* ptr= fast_new (sizeof (C));
(void) new (ptr) C (a1, a2);
return (C*) ptr;
}

template<typename C> inline void
tm_delete (C* ptr) {
ptr->~C();
fast_delete((void*) ptr);
}

struct Complex {
public:
double re, im;
Complex(double re_, double im_): re(re_), im(im_) {}
~Complex() {}
};

int main(int argc, char* argv[]) {
char* p_char = tm_new<char>('a');
tm_delete(p_char);
Complex* p_complex = tm_new<Complex>(35.8, 26.2);
p_char = tm_new<char>('b');

char* p_char1 = tm_new<char>('c');

tm_delete(p_complex);
tm_delete(p_char);
tm_delete(p_char1);
return 0;
}
0
显示全文

查看更多有趣的豆瓣小组

回应

还没人回应,我来添加

推荐小组

值得一读

    豆瓣
    我们的精神角落
    免费下载 iOS / Android 版客户端