C/C++ 最容易出问题的地方是内存管理,容易造成内存泄露和内存越界,这一直是 C/C++ 程序员比较头疼的事情,但 C/C++ 最大的优势也是内存管理,可以让程序员直接管理内存,从而使程序运行更为高效。acl 库中的内存池管理器 dbuf_guard 在管理内存的效率上比系统级内存管理方式(malloc/free, new/delete)更为高效,同时也使内存管理更为健壮性,这可以使 C/C++ 程序员避免出现一些常见的内存问题。本节主要介绍了 acl 库中 dbuf_guard 类的设计特点及使用方法。
dbuf_guard 类内部封装了内存池对象类 dbuf_pool,提供了与 dbuf_pool 一样的内存分配方法,dbuf_guard 类与 dbuf_pool 类的最大区别是 dbuf_guard 类对象既可以在堆上动态分配,也可以在栈上分配,而 dbuf_pool 类对象必须在堆上动态分配,另外,dbuf_guard 类还统一管理在 dbuf_pool 内存池上所创建的所有 dbuf_obj 子类对象,在 dbuf_guard 类对象析构时,所有由其管理的 dbuf_obj 子类对象被统一析构。下面先从一个简单的例子来说明 dbuf_guard 的使用方法,例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void test(void) { acl::dbuf_guard dbuf;
#define STR "hello world"
char* str = dbuf.dbuf_strdup(STR); printf("str: %s\r\n", str);
str = (char*) dbuf.dbuf_alloc(sizeof(STR)); memcpy(str, STR, sizeof(STR)); printf("str: %s\r\n", str);
}
|
上面的例子展示了使用 dbuf_guard 类对象直接分配内存块的过程,可以看出,所有在 dbuf_guard 对象的内存池上动态分配的内存都会在 dbuf_guard 对象销毁时被自动释放。这只是一个简单的使用 dbuf_guard 进行内存管理的例子,那么对于 C++ 对象的内存如何进行管理呢?请看下面的的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class myobj : public acl::dbuf_obj { public: myobj() { str_ = strdup("hello world"); }
void run() { printf("str: %s\r\n", str_); }
private: char* str_;
~myobj() { free(str_); } };
void test(void) { acl::dbuf_guard dbuf;
myobj* obj = dbuf.create<myobj>();
obj->run();
}
|
该例子展示了 C++ 对象在 dbuf_guard 动态创建的过程,其中有两个要点:
- 由 dbuf_guard 对象统一管理的 C++ 对象必须是 dbuf_obj 的子类,这样在 dbuf_guard 类对象的析构时才可以通过调用 dbuf_obj 的析构函数来达到将 dbuf_obj 子类析构的目的(其中 dbuf_obj 的析构函数为虚函数);
- 创建 dbuf_obj 的子类对象时,调用 dbuf_guard 对象的模板函数 create,同时指定子类名称 myobj 来创建 myobj 对象,create 内部会自动将该对象指针加入内部数组对象集合中,从而达到统一管理的目的。
上面例子的构造函数不带参数,在 dbuf_guard::create 模板函数中允许添加 0 至 10 个参数(其实内部有 11 个 create 模板函数),如果一个构造函数需要多于 10 个参数,则说明该构造函数设计的太复杂了。下面的例子展示了构造函数带参数的类对象创建过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class myobj : public acl::dbuf_obj { public: myobj(int i, int j) { printf("myobj, i=%d, j=%d\r\n", i, j); str_ = dbuf.dbuf_strdup("hello world"); }
void run() { printf("str: %s\r\n", str_); }
private: char* str_;
~myobj() { } };
void test(void) { acl::dbuf_guard dbuf;
myobj* obj = dbuf.create<myobj>(10, 100);
obj->run();
}
|
在 dbuf_guard 类中除了上面提供的方法外,还提供了以下多个方法方便使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
bool dbuf_reset(size_t reserve = 0) { return dbuf_->dbuf_reset(reserve); }
void* dbuf_alloc(size_t len) { return dbuf_->dbuf_alloc(len); }
void* dbuf_calloc(size_t len) { return dbuf_->dbuf_calloc(len); }
char* dbuf_strdup(const char* s) { return dbuf_->dbuf_strdup(s); }
char* dbuf_strndup(const char* s, size_t len) { return dbuf_->dbuf_strndup(s, len); }
void* dbuf_memdup(const void* addr, size_t len) { return dbuf_->dbuf_memdup(addr, len); }
bool dbuf_free(const void* addr) { return dbuf_->dbuf_free(addr); }
bool dbuf_keep(const void* addr) { return dbuf_->dbuf_keep(addr); }
bool dbuf_unkeep(const void* addr) { return dbuf_->dbuf_unkeep(addr); }
acl::dbuf_pool& get_dbuf() const { return *dbuf_; }
int push_back(dbuf_obj* obj);
size_t size() const { return size_; }
dbuf_obj** get_objs() const { return objs_; }
dbuf_obj* operator[](size_t pos) const;
dbuf_obj* get(size_t pos) const;
void set_increment(size_t incr);
同时,dbuf_obj 类中也提供了额外的操作方法:
int pos() const { return pos_; }
dbuf_guard* get_guard() const { return guard_; }
|
最后,以一个稍微复杂的例子做为结尾(该例子源码在 acl 库中的位置:lib_acl_cpp\samples\dbuf\dbuf2),该例子展示了使用 dbuf_guard 类的几种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
| #include "stdafx.h" #include <sys/time.h>
class myobj : public acl::dbuf_obj { public: myobj(acl::dbuf_guard* guard = NULL) : dbuf_obj(guard) { ptr_ = strdup("hello"); }
void run() { printf("----> run->hello world <-----\r\n"); }
private: char* ptr_;
~myobj() { free(ptr_); } };
static void test_dbuf(acl::dbuf_guard& dbuf) { for (int i = 0; i < 102400; i++) { char* ptr = (char*) dbuf.dbuf_alloc(10); (void) ptr; }
for (int i = 0; i < 102400; i++) { char* str = dbuf.dbuf_strdup("hello world"); if (i < 5) printf(">>str->%s\r\n", str); }
(void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(2048); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(10240);
for (int i = 0; i < 10000; i++) {
myobj* obj = dbuf.create<myobj>(&dbuf);
assert(obj == dbuf[obj->pos()]);
if (i < 10) obj->run(); }
for (int i = 0; i < 10000; i++) { myobj* obj = dbuf.create<myobj>();
assert(dbuf[obj->pos()] == obj);
if (i < 10) obj->run(); }
for (int i = 0; i < 10000; i++) { myobj* obj = dbuf.create<myobj>(&dbuf);
(void) dbuf.push_back(obj); (void) dbuf.push_back(obj); (void) dbuf.push_back(obj);
assert(obj == dbuf[obj->pos()]);
if (i < 10) obj->run(); } }
static void wait_pause() { printf("Enter any key to continue ..."); fflush(stdout); getchar(); }
static void test1() { acl::dbuf_guard dbuf;
test_dbuf(dbuf); }
static void test2() { acl::dbuf_guard* dbuf = new acl::dbuf_guard;
test_dbuf(*dbuf);
delete dbuf; }
static void test3() { acl::dbuf_guard dbuf(new acl::dbuf_pool);
test_dbuf(dbuf); }
static void test4() { acl::dbuf_guard dbuf(10, 100);
test_dbuf(dbuf); }
static void test5() { acl::dbuf_pool* dp = new acl::dbuf_pool;
acl::dbuf_guard* dbuf = new (dp->dbuf_alloc(sizeof(acl::dbuf_guard))) acl::dbuf_guard(dp);
test_dbuf(*dbuf);
dbuf->~dbuf_guard(); }
class myobj2 : public acl::dbuf_obj { public: myobj2() {}
void run() { printf("hello world\r\n"); }
private: ~myobj2() {} };
class myobj3 : public acl::dbuf_obj { public: myobj3(int i) : i_(i) {}
void run() { printf("hello world: %d\r\n", i_); }
private: ~myobj3() {}
private: int i_; };
class myobj_dummy { public: myobj_dummy() {}
void run() { printf("can't be compiled\r\n"); }
private: ~myobj_dummy() {} };
static void test6() { acl::dbuf_guard dbuf;
myobj* o = dbuf.create<myobj>(); o->run();
myobj* o1 = dbuf.create<myobj>(&dbuf); o1->run();
myobj2* o2 = dbuf.create<myobj2>(); o2->run();
myobj3* o3 = dbuf.create<myobj3>(10); o3->run();
for (int i = 0; i < 10; i++) { myobj3* o4 = dbuf.create<myobj3>(i); o4->run(); }
}
int main(void) { acl::log::stdout_open(true);
test1(); wait_pause();
test2(); wait_pause();
test3(); wait_pause();
test4(); wait_pause();
test5(); wait_pause();
test6(); return 0; }
|
github:https://github.com/acl-dev/acl
gitee:https://gitee.com/acl-dev/acl