myicq 1.0中实现了一个内存池的模型,可以自动分配和回收对象内存。下面看下其实现方式。
首先内存池使用了双向链表来链接的,链表的实现也就是linux中常见的list_head形式,不过是其自己实现的。
有点不解的是,既然用list_head,如果是在linux实现,可以自己调用linux里内建好的list_head,而且还是C的呢,而不是myicq里自己实现的还是类的形式的。又如果如果说是在windows下,那windows下的vc也有类似的形式如:FILED_OFFSET宏就是这样。
感觉在这里用刻意使用list_head,而又是以类的形式使用,我感觉还不如直接使用stl来得方便,或者说代码阅读性好很多。
不多说了,看代码。
myicq里的ListHead
list.h
view plaincopy to clipboardprint?
01./***************************************************************************
02. * *
03. * This program is free software; you can redistribute it and/or modify *
04. * it under the terms of the GNU General Public License as published by *
05. * the Free Software Foundation; either version 2 of the License, or *
06. * (at your option) any later version. *
07. * *
08. * copyright : (C) 2002 by Zhang Yong *
09. * email : z-yong163@163.com *
10. ***************************************************************************/
11.#ifndef _LIST_H_
12.#define _LIST_H_
13.#include "icqtypes.h"
14.#define LIST_ENTRY(ptr, type, member) /
15. ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
16.#define LIST_FOR_EACH(pos, head) /
17. for (pos = (head)->next; pos != (head); pos = pos->next)
18./*
19. * 这是一个循环链表
20. */
21.class ListHead {
22.public:
23. ListHead() {
24. prev = next = this;
25. }
26. bool isEmpty() {
27. return (next == this);
28. }
29. ListHead *removeHead();
30. void add(ListHead *item);
31. void addHead(ListHead *item);
32. void remove();
33. ListHead *prev, *next;
34.};
35.#endif
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright : (C) 2002 by Zhang Yong *
* email : z-yong163@163.com *
***************************************************************************/
#ifndef _LIST_H_
#define _LIST_H_
#include "icqtypes.h"
#define LIST_ENTRY(ptr, type, member) /
((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
#define LIST_FOR_EACH(pos, head) /
for (pos = (head)->next; pos != (head); pos = pos->next)
/*
* 这是一个循环链表
*/
class ListHead {
public:
ListHead() {
prev = next = this;
}
bool isEmpty() {
return (next == this);
}
ListHead *removeHead();
void add(ListHead *item);
void addHead(ListHead *item);
void remove();
ListHead *prev, *next;
};
#endif
list.cpp
view plaincopy to clipboardprint?
01./***************************************************************************
02. * *
03. * This program is free software; you can redistribute it and/or modify *
04. * it under the terms of the GNU General Public License as published by *
05. * the Free Software Foundation; either version 2 of the License, or *
06. * (at your option) any later version. *
07. * *
08. * copyright : (C) 2002 by Zhang Yong *
09. * email : z-yong163@163.com *
10. ***************************************************************************/
11.#include "list.h"
12./*
13. * 让this节点孤立起来
14. */
15.void ListHead::remove()
16.{
17. prev->next = next;
18. next->prev = prev;
19. prev = next = this;
20.}
21./*
22. * 将this后面的节点孤立起来,并返回这个节点
23. */
24.ListHead *ListHead::removeHead()
25.{
26. ListHead *t = next;
27. next->remove();
28. return t;
29.}
30./*
31. * 在this前加入item
32. */
33.void ListHead::add(ListHead *item)
34.{
35. item->prev = prev;
36. item->next = this;
37. prev->next = item;
38. prev = item;
39.}
40./*
41. * 在this后面加入节点item
42. */
43.void ListHead::addHead(ListHead *item)
44.{
45. item->prev = this;
46. item->next = next;
47. next->prev = item;
48. next = item;
49.}
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright : (C) 2002 by Zhang Yong *
* email : z-yong163@163.com *
***************************************************************************/
#include "list.h"
/*
* 让this节点孤立起来
*/
void ListHead::remove()
{
prev->next = next;
next->prev = prev;
prev = next = this;
}
/*
* 将this后面的节点孤立起来,并返回这个节点
*/
ListHead *ListHead::removeHead()
{
ListHead *t = next;
next->remove();
return t;
}
/*
* 在this前加入item
*/
void ListHead::add(ListHead *item)
{
item->prev = prev;
item->next = this;
prev->next = item;
prev = item;
}
/*
* 在this后面加入节点item
*/
void ListHead::addHead(ListHead *item)
{
item->prev = this;
item->next = next;
next->prev = item;
next = item;
}
这样就实现了一个简单的双向链表,如果对list_head机制不熟的可以看我的文章《深入浅出linux内核源代码之双向链表list_head(上)》 和《 深入浅出linux内核源代码之双向链表list_head(下) 》。
下面是一个内存池的实现方式:
slab.h
view plaincopy to clipboardprint?
01./***************************************************************************
02. * *
03. * This program is free software; you can redistribute it and/or modify *
04. * it under the terms of the GNU General Public License as published by *
05. * the Free Software Foundation; either version 2 of the License, or *
06. * (at your option) any later version. *
07. * *
08. * copyright : (C) 2002 by Zhang Yong *
09. * email : z-yong163@163.com *
10. ***************************************************************************/
11.#ifndef _SLAB_H
12.#define _SLAB_H
13.#include "list.h"
14.#include <stdio.h>
15.struct SLAB;
16.struct OBJ {
17. OBJ *next;
18. SLAB *slab;
19.};
20.struct SLAB {
21. ListHead item;
22. int inuse;
23. OBJ *free;
24.};
25.class Cache {
26.public:
27. Cache(int size, int n);
28. ~Cache();
29. void *allocObj();
30. void freeObj(void *p);
31. static int reclaimAll();
32.private:
33. SLAB *newSlab();
34. int reclaim(int n = 0xffff);
35. Cache *nextCache;
36. ListHead slabList;
37. ListHead *firstNotFull;
38. int objSize;
39. int numObjs;
40. int numFreeSlabs;
41. int slabSize;
42. static Cache *cacheList;
43.};
44.#define DECLARE_SLAB(type) /
45.private: /
46. static Cache type##_cache; /
47.public: /
48. void *operator new(size_t) { /
49. return type##_cache.allocObj(); /
50. } /
51. void operator delete(void *p) { /
52. type##_cache.freeObj(p); /
53. }
54.#define IMPLEMENT_SLAB(type, num) /
55. Cache type::type##_cache(sizeof(type), num);
56.#endif
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright : (C) 2002 by Zhang Yong *
* email : z-yong163@163.com *
***************************************************************************/
#ifndef _SLAB_H
#define _SLAB_H
#include "list.h"
#include <stdio.h>
struct SLAB;
struct OBJ {
OBJ *next;
SLAB *slab;
};
struct SLAB {
ListHead item;
int inuse;
OBJ *free;
};
class Cache {
public:
Cache(int size, int n);
~Cache();
void *allocObj();
void freeObj(void *p);
static int reclaimAll();
private:
SLAB *newSlab();
int reclaim(int n = 0xffff);
Cache *nextCache;
ListHead slabList;
ListHead *firstNotFull;
int objSize;
int numObjs;
int numFreeSlabs;
int slabSize;
static Cache *cacheList;
};
#define DECLARE_SLAB(type) /
private: /
static Cache type##_cache; /
public: /
void *operator new(size_t) { /
return type##_cache.allocObj(); /
} /
void operator delete(void *p) { /
type##_cache.freeObj(p); /
}
#define IMPLEMENT_SLAB(type, num) /
Cache type::type##_cache(sizeof(type), num);
#endif
slab.cpp
view plaincopy to clipboardprint?
01./***************************************************************************
02. * *
03. * This program is free software; you can redistribute it and/or modify *
04. * it under the terms of the GNU General Public License as published by *
05. * the Free Software Foundation; either version 2 of the License, or *
06. * (at your option) any later version. *
07. * *
08. * copyright : (C) 2002 by Zhang Yong *
09. * email : z-yong163@163.com *
10. ***************************************************************************/
11.#include "slab.h"
12.#include <stdlib.h>
13.#include <memory.h>
14.#define MAX_FREE_SLABS 8
15.Cache *Cache::cacheList = NULL;
16.int Cache::reclaimAll()
17.{
18. int ret = 0;
19. for (Cache *p = cacheList; p; p = p->nextCache)
20. ret += p->reclaim();
21. return ret;
22.}
23.Cache::Cache(int size, int n)
24.{
25. objSize = size + sizeof(OBJ);
26. numObjs = n;
27. numFreeSlabs = 0;
28. firstNotFull = &slabList;
29. slabSize = sizeof(SLAB) + objSize * n;
30. // Add it to the cache chain
31. nextCache = cacheList;
32. cacheList = this;
33.}
34.Cache::~Cache()
35.{
36. while (!slabList.isEmpty()) {
37. ListHead *pos = slabList.removeHead();
38. SLAB *slab = LIST_ENTRY(pos, SLAB, item);
39. free(slab);
40. }
41.}
42./*
43. * Reclaim empty slabs in this cache
44. */
45.int Cache::reclaim(int n)
46.{
47. SLAB *slab;
48. ListHead *pos, *t = firstNotFull;
49. int i = 0;
50. while (i < n && (pos = slabList.prev) != &slabList) {
51. slab = LIST_ENTRY(pos, SLAB, item);
52. if (slab->inuse)
53. break;
54. i++;
55. if (firstNotFull == pos)
56. firstNotFull = pos->prev;
57. pos->remove();
58. free(slab);
59. }
60. if (firstNotFull != t && firstNotFull != &slabList) {
61. slab = LIST_ENTRY(firstNotFull, SLAB, item);
62. if (slab->inuse == numObjs)
63. firstNotFull = &slabList;
64. }
65. numFreeSlabs += i;
66. return i;
67.}
68./*
69. * Alloc a new slab
70. */
71.SLAB *Cache::newSlab()
72.{
73. SLAB *slab = (SLAB *) malloc(slabSize);
74. if (!slab) {
75. if (reclaimAll() > 0) {
76. slab = (SLAB *) malloc(slabSize);
77. if (!slab)
78. return NULL;
79. }
80. }
81. slab->inuse = 0;
82. OBJ *obj = (OBJ *) (slab + 1);
83. slab->free = obj;
84. for (int i = 0; i < numObjs - 1; ++i) {
85. OBJ *next = (OBJ *) ((char *) obj + objSize);
86. obj->next = next;
87. obj->slab = slab;
88. obj = next;
89. }
90. obj->next = NULL;
91. obj->slab = slab;
92. slabList.add(&slab->item);
93. firstNotFull = &slab->item;
94. return slab;
95.}
96./*
97. * Alloc an object from the cache
98. */
99.void *Cache::allocObj()
100.{
101. void *obj = NULL;
102. SLAB *slab;
103. if (firstNotFull == &slabList)
104. slab = newSlab();
105. else {
106. slab = LIST_ENTRY(firstNotFull, SLAB, item);
107. if (!slab->inuse)
108. numFreeSlabs--;
109. }
110. if (slab) {
111. slab->inuse++;
112. obj = slab->free + 1;
113. slab->free = slab->free->next;
114. if (!slab->free)
115. firstNotFull = slab->item.next;
116. }
117. return obj;
118.}
119./*
120. * Free an object in the cache
121. */
122.void Cache::freeObj(void *p)
123.{
124.#ifdef _DEBUG
125. memset(p, 0xdd, objSize - sizeof(OBJ));
126.#endif
127. OBJ *obj = (OBJ *) p - 1;
128. SLAB *slab = obj->slab;
129. obj->next = slab->free;
130. slab->free = obj;
131. ListHead *pos;
132. if (slab->inuse-- == numObjs) {
133. ListHead *t = firstNotFull;
134. pos = &slab->item;
135. firstNotFull = pos;
136. if (pos->next != t) {
137. pos->remove();
138. t->add(pos);
139. }
140. } else if (!slab->inuse) {
141. int n = ++numFreeSlabs - MAX_FREE_SLABS;
142. if (n > 0)
143. reclaim(n);
144. ListHead *t = firstNotFull->prev;
145. pos = &slab->item;
146. pos->remove();
147. slabList.add(pos);
148. if (firstNotFull == &slab->item)
149. firstNotFull = t->next;
150. }
151.}
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright : (C) 2002 by Zhang Yong *
* email : z-yong163@163.com *
***************************************************************************/
#include "slab.h"
#include <stdlib.h>
#include <memory.h>
#define MAX_FREE_SLABS 8
Cache *Cache::cacheList = NULL;
int Cache::reclaimAll()
{
int ret = 0;
for (Cache *p = cacheList; p; p = p->nextCache)
ret += p->reclaim();
return ret;
}
Cache::Cache(int size, int n)
{
objSize = size + sizeof(OBJ);
numObjs = n;
numFreeSlabs = 0;
firstNotFull = &slabList;
slabSize = sizeof(SLAB) + objSize * n;
// Add it to the cache chain
nextCache = cacheList;
cacheList = this;
}
Cache::~Cache()
{
while (!slabList.isEmpty()) {
ListHead *pos = slabList.removeHead();
SLAB *slab = LIST_ENTRY(pos, SLAB, item);
free(slab);
}
}
/*
* Reclaim empty slabs in this cache
*/
int Cache::reclaim(int n)
{
SLAB *slab;
ListHead *pos, *t = firstNotFull;
int i = 0;
while (i < n && (pos = slabList.prev) != &slabList) {
slab = LIST_ENTRY(pos, SLAB, item);
if (slab->inuse)
break;
i++;
if (firstNotFull == pos)
firstNotFull = pos->prev;
pos->remove();
free(slab);
}
if (firstNotFull != t && firstNotFull != &slabList) {
slab = LIST_ENTRY(firstNotFull, SLAB, item);
if (slab->inuse == numObjs)
firstNotFull = &slabList;
}
numFreeSlabs += i;
return i;
}
/*
* Alloc a new slab
*/
SLAB *Cache::newSlab()
{
SLAB *slab = (SLAB *) malloc(slabSize);
if (!slab) {
if (reclaimAll() > 0) {
slab = (SLAB *) malloc(slabSize);
if (!slab)
return NULL;
}
}
slab->inuse = 0;
OBJ *obj = (OBJ *) (slab + 1);
slab->free = obj;
for (int i = 0; i < numObjs - 1; ++i) {
OBJ *next = (OBJ *) ((char *) obj + objSize);
obj->next = next;
obj->slab = slab;
obj = next;
}
obj->next = NULL;
obj->slab = slab;
slabList.add(&slab->item);
firstNotFull = &slab->item;
return slab;
}
/*
* Alloc an object from the cache
*/
void *Cache::allocObj()
{
void *obj = NULL;
SLAB *slab;
if (firstNotFull == &slabList)
slab = newSlab();
else {
slab = LIST_ENTRY(firstNotFull, SLAB, item);
if (!slab->inuse)
numFreeSlabs--;
}
if (slab) {
slab->inuse++;
obj = slab->free + 1;
slab->free = slab->free->next;
if (!slab->free)
firstNotFull = slab->item.next;
}
return obj;
}
/*
* Free an object in the cache
*/
void Cache::freeObj(void *p)
{
#ifdef _DEBUG
memset(p, 0xdd, objSize - sizeof(OBJ));
#endif
OBJ *obj = (OBJ *) p - 1;
SLAB *slab = obj->slab;
obj->next = slab->free;
slab->free = obj;
ListHead *pos;
if (slab->inuse-- == numObjs) {
ListHead *t = firstNotFull;
pos = &slab->item;
firstNotFull = pos;
if (pos->next != t) {
pos->remove();
t->add(pos);
}
} else if (!slab->inuse) {
int n = ++numFreeSlabs - MAX_FREE_SLABS;
if (n > 0)
reclaim(n);
ListHead *t = firstNotFull->prev;
pos = &slab->item;
pos->remove();
slabList.add(pos);
if (firstNotFull == &slab->item)
firstNotFull = t->next;
}
}
内存池是SLAB结构打头的一个大块内存,里面有多个对象内存快,这些内存快个数在下面的#define IMPLEMENT_SLAB(type, num) 宏中的num来指定个数,每个对象空间前面有个OBJ的结构头部。
SLAB后面是连续的OBJ内存快,SLAB结构里的free指向第一个可使用的对象内存快。在回收内存块时这个free指针会指向回收的这块内存,而这块内存会指向free指向的内存块,形成一个可用内存快链表。而内存快又是以next的形式链接在一起。这种实现形式和SGI的STL的内存池的实现非常相似,具体可以参考侯捷的《内存春秋》里说的,里面说得非常详细易懂!
cache类是一个以list_head来链接的双向链表,其链接的是SLAB结构的内存块。
#define DECLARE_SLAB(type) 宏用在类中声明一个静态变量static Cache type##_cache;并且里面重新定义了new和delete,以便从内存池中分配和销毁。
#define IMPLEMENT_SLAB(type, num) 宏用来类的定义出定义这个静态变量,type用于制定对象大小,num用于指定分配多少个快
下面是类DBRequest中使用了这个内存池:
dbmanager.h
view plaincopy to clipboardprint?
01./***************************************************************************
02. * *
03. * This program is free software; you can redistribute it and/or modify *
04. * it under the terms of the GNU General Public License as published by *
05. * the Free Software Foundation; either version 2 of the License, or *
06. * (at your option) any later version. *
07. * *
08. * copyright : (C) 2002 by Zhang Yong *
09. * email : z-yong163@163.com *
10. ***************************************************************************/
11.#ifndef _DB_MANAGER_H
12.#define _DB_MANAGER_H
13.#include <mysql.h>
14.#include "myicq.h"
15.#include "list.h"
16.#include "slab.h"
17.#define WRITE_STR(req, str) req->writeString(str, sizeof(str) - 1)
18.#define MAX_SQL 4096
19.extern MYSQL *mysqlWrite;
20.char *conv10(uint32 num, char *bufEnd);
21.class RefObject;
22.class DBRequest;
23.typedef void (*DB_CALLBACK)(DBRequest *req);
24.enum {
25. DBF_UPDATE = 0x01,
26. DBF_INSERT = 0x02,
27.};
28.class DBRequest {
29.friend class DBManager;
30.public:
31. DBRequest(uint8 flags, DB_CALLBACK cb = NULL, RefObject *obj = NULL, uint32 d = 0);
32. void writeString(const char *text, int n) {
33. if (cursor - sql + n <= MAX_SQL) {
34. memcpy(cursor, text, n);
35. cursor += n;
36. }
37. }
38. DBRequest &operator <<(ICQ_STR &str) {
39. if (cursor - sql + (str.len << 1) < MAX_SQL - 2) {
40. *cursor++ = '/'';
41. cursor += mysql_real_escape_string(mysqlWrite, cursor, str.text, str.len);
42. *cursor++ = '/'';
43. }
44. return *this;
45. }
46. DBRequest &operator <<(char c) {
47. if (cursor - sql <= (int) (MAX_SQL - sizeof(c)))
48. *cursor++ = c;
49. return *this;
50. }
51. DBRequest &operator <<(uint8 num) {
52. *this << (uint32) num;
53. return *this;
54. }
55. DBRequest &operator <<(uint16 num) {
56. *this <<(uint32) num;
57. return *this;
58. }
59. DBRequest &operator <<(uint32 num) {
60. char buf[16];
61. char *p = conv10(num, buf + sizeof(buf));
62. writeString(p, buf + sizeof(buf) - p);
63. return *this;
64. }
65. ListHead listItem;
66. DB_CALLBACK callback;
67. RefObject *refObj;
68. uint32 data;
69. union {
70. MYSQL_RES *res;
71. int ret;
72. };
73. uint32 lastInsertID;
74.private:
75. int sqlLen() {
76. return cursor - sql;
77. }
78. uint8 flags;
79. char sql[MAX_SQL];
80. char *cursor;
81. DECLARE_SLAB(DBRequest)
82.};
83.class DBManager {
84.public:
85. DBManager();
86. ~DBManager();
87. bool create(DB_INFO &dbSlave);
88. void processQuery();
89. static bool init(DB_INFO &dbMaster);
90. static void destroy();
91. static void query(DBRequest *req);
92. static void processUpdate();
93. static void dispatch();
94.private:
95. MYSQL *mysqlRead;
96.};
97.#endif
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright : (C) 2002 by Zhang Yong *
* email : z-yong163@163.com *
***************************************************************************/
#ifndef _DB_MANAGER_H
#define _DB_MANAGER_H
#include <mysql.h>
#include "myicq.h"
#include "list.h"
#include "slab.h"
#define WRITE_STR(req, str) req->writeString(str, sizeof(str) - 1)
#define MAX_SQL 4096
extern MYSQL *mysqlWrite;
char *conv10(uint32 num, char *bufEnd);
class RefObject;
class DBRequest;
typedef void (*DB_CALLBACK)(DBRequest *req);
enum {
DBF_UPDATE = 0x01,
DBF_INSERT = 0x02,
};
class DBRequest {
friend class DBManager;
public:
DBRequest(uint8 flags, DB_CALLBACK cb = NULL, RefObject *obj = NULL, uint32 d = 0);
void writeString(const char *text, int n) {
if (cursor - sql + n <= MAX_SQL) {
memcpy(cursor, text, n);
cursor += n;
}
}
DBRequest &operator <<(ICQ_STR &str) {
if (cursor - sql + (str.len << 1) < MAX_SQL - 2) {
*cursor++ = '/'';
cursor += mysql_real_escape_string(mysqlWrite, cursor, str.text, str.len);
*cursor++ = '/'';
}
return *this;
}
DBRequest &operator <<(char c) {
if (cursor - sql <= (int) (MAX_SQL - sizeof(c)))
*cursor++ = c;
return *this;
}
DBRequest &operator <<(uint8 num) {
*this << (uint32) num;
return *this;
}
DBRequest &operator <<(uint16 num) {
*this <<(uint32) num;
return *this;
}
DBRequest &operator <<(uint32 num) {
char buf[16];
char *p = conv10(num, buf + sizeof(buf));
writeString(p, buf + sizeof(buf) - p);
return *this;
}
ListHead listItem;
DB_CALLBACK callback;
RefObject *refObj;
uint32 data;
union {
MYSQL_RES *res;
int ret;
};
uint32 lastInsertID;
private:
int sqlLen() {
return cursor - sql;
}
uint8 flags;
char sql[MAX_SQL];
char *cursor;
DECLARE_SLAB(DBRequest)
};
class DBManager {
public:
DBManager();
~DBManager();
bool create(DB_INFO &dbSlave);
void processQuery();
static bool init(DB_INFO &dbMaster);
static void destroy();
static void query(DBRequest *req);
static void processUpdate();
static void dispatch();
private:
MYSQL *mysqlRead;
};
#endif
可以看到在类的最后使用了DECLARE_SLAB(DBRequest)来声明。
并且在dbmanager.cpp中调用IMPLEMENT_SLAB(DBRequest, 16)来实现,可以看到每次分配是16个对象。
如果使用满了,会在获取下一个空余对象空间时,自动在cache里在分配一个slab内存快,然后以list_head的双向链表形式链接起来。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fjb2080/archive/2011/06/15/6546858.aspx