【redis源码】(一)Zmalloc
Zmalloc是redis的基础,redis源码的阅读从Zmalloc开始,相信这个一个愉快的旅程,读优秀的代码,就像听音乐~ 好了开始吧
头文件 Zmalloc.h,没什么好说的,声明了一些函数,具体的实现见Zmalloc.c
1: #ifndef _ZMALLOC_H
2: #define _ZMALLOC_H
3:
4: void *zmalloc(size_t size);
5: void *zcalloc(size_t size);
6: void *zrealloc(void *ptr, size_t size);
7: void zfree(void *ptr);
8: char *zstrdup(const char *s);
9: size_t zmalloc_used_memory(void);
10: void zmalloc_enable_thread_safeness(void);
11: float zmalloc_get_fragmentation_ratio(void);
12: size_t zmalloc_get_rss(void);
13:
14: #endif /* _ZMALLOC_H */
Zmalloc.c
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4: #include <pthread.h>
5: #include "config.h"
6: #include "zmalloc.h"
7:
8:
9: //PREFIX_SIZE用来记录malloc拿到的内存块的size,如果使用了google的tcmalloc库或者苹果的环境,可以使用系统函数获得内存块的大小,就不用这个区域来记录
10: #ifdef HAVE_MALLOC_SIZE
11: #define PREFIX_SIZE (0)
12: #else
13: #if defined(__sun)
14: #define PREFIX_SIZE (sizeof(long long))
15: #else
16: #define PREFIX_SIZE (sizeof(size_t))
17: #endif
18: #endif
19:
20: /* Explicitly override malloc/free etc when using tcmalloc. */
21: //使用google的tcmalloc库作为底层的malloc函数
22: #if defined(USE_TCMALLOC)
23: #define malloc(size) tc_malloc(size)
24: #define calloc(count,size) tc_calloc(count,size)
25: #define realloc(ptr,size) tc_realloc(ptr,size)
26: #define free(ptr) tc_free(ptr)
27: #endif
28:
29: //Zmalloc会在全局静态变量里记录已经申请的内存大小 static size_t used_memory = 0;
30: #define update_zmalloc_stat_alloc(__n,__size) do { \
31: size_t _n = (__n); \
32: //将记录的内存大小补齐sizeof(long)的倍数
33: if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
34: if (zmalloc_thread_safe) { \
35: pthread_mutex_lock(&used_memory_mutex); \
36: used_memory += _n; \
37: pthread_mutex_unlock(&used_memory_mutex); \
38: } else { \
39: used_memory += _n; \
40: } \
41: } while(0)
42:
43: #define update_zmalloc_stat_free(__n) do { \
44: size_t _n = (__n); \
45: if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
46: if (zmalloc_thread_safe) { \
47: pthread_mutex_lock(&used_memory_mutex); \
48: used_memory -= _n; \
49: pthread_mutex_unlock(&used_memory_mutex); \
50: } else { \
51: used_memory -= _n; \
52: } \
53: } while(0)
54:
55: static size_t used_memory = 0;
56: static int zmalloc_thread_safe = 0;
57: pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
58:
59: //如果申请内存失败,发送SIGABRT信号通知程序
60: static void zmalloc_oom(size_t size) {
61: fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
62: size);
63: fflush(stderr);
64: abort();
65: }
66:
67: //申请size大bytes的内存区域
68: void *zmalloc(size_t size) {
69: //实际申请size+PREFIX_SIZE大小的内存空间,其中,前PREFIX_SIZE的空间用来记录内存块大小
70: void *ptr = malloc(size+PREFIX_SIZE);
71:
72: if (!ptr) zmalloc_oom(size);
73: #ifdef HAVE_MALLOC_SIZE
74: update_zmalloc_stat_alloc(redis_malloc_size(ptr),size);
75: return ptr;
76: #else
77: //记录内存块大小
78: *((size_t*)ptr) = size;
79: update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);
80: return (char*)ptr+PREFIX_SIZE;
81: #endif
82: }
83:
84: //申请size个sizeof(byte)大的内存区域
85: void *zcalloc(size_t size) {
86: void *ptr = calloc(1, size+PREFIX_SIZE);
87:
88: if (!ptr) zmalloc_oom(size);
89: #ifdef HAVE_MALLOC_SIZE
90: update_zmalloc_stat_alloc(redis_malloc_size(ptr),size);
91: return ptr;
92: #else
93: *((size_t*)ptr) = size;
94: update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);
95: return (char*)ptr+PREFIX_SIZE;
96: #endif
97: }
98:
99: //重新分配size大小的内存
100: void *zrealloc(void *ptr, size_t size) {
101: #ifndef HAVE_MALLOC_SIZE
102: void *realptr;
103: #endif
104: size_t oldsize;
105: void *newptr;
106:
107: if (ptr == NULL) return zmalloc(size);
108: #ifdef HAVE_MALLOC_SIZE
109: oldsize = redis_malloc_size(ptr);
110: newptr = realloc(ptr,size);
111: if (!newptr) zmalloc_oom(size);
112:
113: update_zmalloc_stat_free(oldsize);
114: update_zmalloc_stat_alloc(redis_malloc_size(newptr),size);
115: return newptr;
116: #else
117: realptr = (char*)ptr-PREFIX_SIZE;
118: oldsize = *((size_t*)realptr);
119: newptr = realloc(realptr,size+PREFIX_SIZE);
120: if (!newptr) zmalloc_oom(size);
121:
122: *((size_t*)newptr) = size;
123: update_zmalloc_stat_free(oldsize);
124: update_zmalloc_stat_alloc(size,size);
125: return (char*)newptr+PREFIX_SIZE;
126: #endif
127: }
128:
129: //释放ptr开始内存块,与zmalloc,zcalloc,zrealloc配对
130: void zfree(void *ptr) {
131: #ifndef HAVE_MALLOC_SIZE
132: void *realptr;
133: size_t oldsize;
134: #endif
135:
136: if (ptr == NULL) return;
137: #ifdef HAVE_MALLOC_SIZE
138: update_zmalloc_stat_free(redis_malloc_size(ptr));
139: free(ptr);
140: #else
141: realptr = (char*)ptr-PREFIX_SIZE;
142: oldsize = *((size_t*)realptr);
143: update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
144: free(realptr);
145: #endif
146: }
147:
148: //复制字符串
149: char *zstrdup(const char *s) {
150: size_t l = strlen(s)+1;
151: char *p = zmalloc(l);
152:
153: memcpy(p,s,l);
154: return p;
155: }
156:
157: //得到已申请内存块总大小
158: size_t zmalloc_used_memory(void) {
159: size_t um;
160:
161: if (zmalloc_thread_safe) pthread_mutex_lock(&used_memory_mutex);
162: um = used_memory;
163: if (zmalloc_thread_safe) pthread_mutex_unlock(&used_memory_mutex);
164: return um;
165: }
166:
167: //设置线程安全zmalloc开关,即操作前lock
168: void zmalloc_enable_thread_safeness(void) {
169: zmalloc_thread_safe = 1;
170: }
171:
172: /* Get the RSS information in an OS-specific way.
173: *
174: * WARNING: the function zmalloc_get_rss() is not designed to be fast
175: * and may not be called in the busy loops where Redis tries to release
176: * memory expiring or swapping out objects.
177: *
178: * For this kind of "fast RSS reporting" usages use instead the
179: * function RedisEstimateRSS() that is a much faster (and less precise)
180: * version of the funciton. */
181:
182: #if defined(HAVE_PROCFS)
183: #include <unistd.h>
184: #include <sys/types.h>
185: #include <sys/stat.h>
186: #include <fcntl.h>
187:
188: size_t zmalloc_get_rss(void) {
189: //获取runtime的信息,获取byte为单位的page大小
190: int page = sysconf(_SC_PAGESIZE);
191: size_t rss;
192: char buf[4096];
193: char filename[256];
194: int fd, count;
195: char *p, *x;
196:
197: snprintf(filename,256,"/proc/%d/stat",getpid());
198: if ((fd = open(filename,O_RDONLY)) == -1) return 0;
199: if (read(fd,buf,4096) <= 0) {
200: close(fd);
201: return 0;
202: }
203: close(fd);
204:
205: p = buf;
206: //获取第24列的占用page的数量信息
207: count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
208: while(p && count--) {
209: p = strchr(p,' ');
210: if (p) p++;
211: }
212: if (!p) return 0;
213: x = strchr(p,' ');
214: if (!x) return 0;
215: *x = '\0';
216:
217: rss = strtoll(p,NULL,10);
218: //得到占用系统内存总量
219: rss *= page;
220: return rss;
221: }
222: #elif defined(HAVE_TASKINFO)
223: #include <unistd.h>
224: #include <stdio.h>
225: #include <stdlib.h>
226: #include <sys/types.h>
227: #include <sys/sysctl.h>
228: #include <mach/task.h>
229: #include <mach/mach_init.h>
230:
231: size_t zmalloc_get_rss(void) {
232: task_t task = MACH_PORT_NULL;
233: struct task_basic_info t_info;
234: mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
235:
236: if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
237: return 0;
238: task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
239:
240: return t_info.resident_size;
241: }
242: #else
243: size_t zmalloc_get_rss(void) {
244: /* If we can't get the RSS in an OS-specific way for this system just
245: * return the memory usage we estimated in zmalloc()..
246: *
247: * Fragmentation will appear to be always 1 (no fragmentation)
248: * of course... */
249: return zmalloc_used_memory();
250: }
251: #endif
252:
253: /* Fragmentation = RSS / allocated-bytes */
254: float zmalloc_get_fragmentation_ratio(void) {
255: return (float)zmalloc_get_rss()/zmalloc_used_memory();
256: }
喜欢一起简单,实用的东西,拒绝复杂花哨,我不是GEEK.