xref: /redis-3.2.3/src/zmalloc.c (revision 9a635431)
1e2641e09Santirez /* zmalloc - total amount of allocated memory aware version of malloc()
2e2641e09Santirez  *
3e2641e09Santirez  * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
4e2641e09Santirez  * All rights reserved.
5e2641e09Santirez  *
6e2641e09Santirez  * Redistribution and use in source and binary forms, with or without
7e2641e09Santirez  * modification, are permitted provided that the following conditions are met:
8e2641e09Santirez  *
9e2641e09Santirez  *   * Redistributions of source code must retain the above copyright notice,
10e2641e09Santirez  *     this list of conditions and the following disclaimer.
11e2641e09Santirez  *   * Redistributions in binary form must reproduce the above copyright
12e2641e09Santirez  *     notice, this list of conditions and the following disclaimer in the
13e2641e09Santirez  *     documentation and/or other materials provided with the distribution.
14e2641e09Santirez  *   * Neither the name of Redis nor the names of its contributors may be used
15e2641e09Santirez  *     to endorse or promote products derived from this software without
16e2641e09Santirez  *     specific prior written permission.
17e2641e09Santirez  *
18e2641e09Santirez  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19e2641e09Santirez  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20e2641e09Santirez  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21e2641e09Santirez  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22e2641e09Santirez  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23e2641e09Santirez  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24e2641e09Santirez  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25e2641e09Santirez  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26e2641e09Santirez  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27e2641e09Santirez  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28e2641e09Santirez  * POSSIBILITY OF SUCH DAMAGE.
29e2641e09Santirez  */
30e2641e09Santirez 
31e2641e09Santirez #include <stdio.h>
32e2641e09Santirez #include <stdlib.h>
33d174eed5Santirez 
34d174eed5Santirez /* This function provide us access to the original libc free(). This is useful
35d174eed5Santirez  * for instance to free results obtained by backtrace_symbols(). We need
36d174eed5Santirez  * to define this function before including zmalloc.h that may shadow the
37d174eed5Santirez  * free implementation if we use jemalloc or another non standard allocator. */
zlibc_free(void * ptr)38d174eed5Santirez void zlibc_free(void *ptr) {
39d174eed5Santirez     free(ptr);
40d174eed5Santirez }
41d174eed5Santirez 
42e2641e09Santirez #include <string.h>
43e2641e09Santirez #include <pthread.h>
44e2641e09Santirez #include "config.h"
4567a1810bSantirez #include "zmalloc.h"
46e2641e09Santirez 
477cdc98b6SPieter Noordhuis #ifdef HAVE_MALLOC_SIZE
487cdc98b6SPieter Noordhuis #define PREFIX_SIZE (0)
49e2641e09Santirez #else
505ae979bfSChris Lamb #if defined(__sun) || defined(__sparc) || defined(__sparc__)
517cdc98b6SPieter Noordhuis #define PREFIX_SIZE (sizeof(long long))
527cdc98b6SPieter Noordhuis #else
537cdc98b6SPieter Noordhuis #define PREFIX_SIZE (sizeof(size_t))
547cdc98b6SPieter Noordhuis #endif
557cdc98b6SPieter Noordhuis #endif
567cdc98b6SPieter Noordhuis 
577cdc98b6SPieter Noordhuis /* Explicitly override malloc/free etc when using tcmalloc. */
587cdc98b6SPieter Noordhuis #if defined(USE_TCMALLOC)
597cdc98b6SPieter Noordhuis #define malloc(size) tc_malloc(size)
607cdc98b6SPieter Noordhuis #define calloc(count,size) tc_calloc(count,size)
617cdc98b6SPieter Noordhuis #define realloc(ptr,size) tc_realloc(ptr,size)
627cdc98b6SPieter Noordhuis #define free(ptr) tc_free(ptr)
6329d04257Santirez #elif defined(USE_JEMALLOC)
6429d04257Santirez #define malloc(size) je_malloc(size)
6529d04257Santirez #define calloc(count,size) je_calloc(count,size)
6629d04257Santirez #define realloc(ptr,size) je_realloc(ptr,size)
6729d04257Santirez #define free(ptr) je_free(ptr)
68e2641e09Santirez #endif
69e2641e09Santirez 
70a953c883SMatt Stancliff #if defined(__ATOMIC_RELAXED)
71a953c883SMatt Stancliff #define update_zmalloc_stat_add(__n) __atomic_add_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
72a953c883SMatt Stancliff #define update_zmalloc_stat_sub(__n) __atomic_sub_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
73a953c883SMatt Stancliff #elif defined(HAVE_ATOMIC)
7480ff1fc6SPremysl Hruby #define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
7580ff1fc6SPremysl Hruby #define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
7680ff1fc6SPremysl Hruby #else
7780ff1fc6SPremysl Hruby #define update_zmalloc_stat_add(__n) do { \
7880ff1fc6SPremysl Hruby     pthread_mutex_lock(&used_memory_mutex); \
7980ff1fc6SPremysl Hruby     used_memory += (__n); \
8080ff1fc6SPremysl Hruby     pthread_mutex_unlock(&used_memory_mutex); \
8180ff1fc6SPremysl Hruby } while(0)
8280ff1fc6SPremysl Hruby 
8380ff1fc6SPremysl Hruby #define update_zmalloc_stat_sub(__n) do { \
8480ff1fc6SPremysl Hruby     pthread_mutex_lock(&used_memory_mutex); \
8580ff1fc6SPremysl Hruby     used_memory -= (__n); \
8680ff1fc6SPremysl Hruby     pthread_mutex_unlock(&used_memory_mutex); \
8780ff1fc6SPremysl Hruby } while(0)
8880ff1fc6SPremysl Hruby 
8980ff1fc6SPremysl Hruby #endif
9080ff1fc6SPremysl Hruby 
91af0b2207Santirez #define update_zmalloc_stat_alloc(__n) do { \
92e2641e09Santirez     size_t _n = (__n); \
93e2641e09Santirez     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
94e2641e09Santirez     if (zmalloc_thread_safe) { \
9580ff1fc6SPremysl Hruby         update_zmalloc_stat_add(_n); \
96e2641e09Santirez     } else { \
97e2641e09Santirez         used_memory += _n; \
98e2641e09Santirez     } \
99e2641e09Santirez } while(0)
100e2641e09Santirez 
10167a1810bSantirez #define update_zmalloc_stat_free(__n) do { \
102e2641e09Santirez     size_t _n = (__n); \
103e2641e09Santirez     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
104e2641e09Santirez     if (zmalloc_thread_safe) { \
10580ff1fc6SPremysl Hruby         update_zmalloc_stat_sub(_n); \
106e2641e09Santirez     } else { \
107e2641e09Santirez         used_memory -= _n; \
108e2641e09Santirez     } \
109e2641e09Santirez } while(0)
110e2641e09Santirez 
111e2641e09Santirez static size_t used_memory = 0;
112e2641e09Santirez static int zmalloc_thread_safe = 0;
113e2641e09Santirez pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
114e2641e09Santirez 
zmalloc_default_oom(size_t size)1156fdc6354Santirez static void zmalloc_default_oom(size_t size) {
116e2641e09Santirez     fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
117e2641e09Santirez         size);
118e2641e09Santirez     fflush(stderr);
119e2641e09Santirez     abort();
120e2641e09Santirez }
121e2641e09Santirez 
1226fdc6354Santirez static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
1236fdc6354Santirez 
zmalloc(size_t size)124e2641e09Santirez void *zmalloc(size_t size) {
125e2641e09Santirez     void *ptr = malloc(size+PREFIX_SIZE);
126e2641e09Santirez 
1276fdc6354Santirez     if (!ptr) zmalloc_oom_handler(size);
128e2641e09Santirez #ifdef HAVE_MALLOC_SIZE
129af0b2207Santirez     update_zmalloc_stat_alloc(zmalloc_size(ptr));
130e2641e09Santirez     return ptr;
131e2641e09Santirez #else
132e2641e09Santirez     *((size_t*)ptr) = size;
133af0b2207Santirez     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
134e2641e09Santirez     return (char*)ptr+PREFIX_SIZE;
135e2641e09Santirez #endif
136e2641e09Santirez }
137e2641e09Santirez 
zcalloc(size_t size)138399f2f40SBenjamin Kramer void *zcalloc(size_t size) {
139399f2f40SBenjamin Kramer     void *ptr = calloc(1, size+PREFIX_SIZE);
140399f2f40SBenjamin Kramer 
1416fdc6354Santirez     if (!ptr) zmalloc_oom_handler(size);
142399f2f40SBenjamin Kramer #ifdef HAVE_MALLOC_SIZE
143af0b2207Santirez     update_zmalloc_stat_alloc(zmalloc_size(ptr));
144399f2f40SBenjamin Kramer     return ptr;
145399f2f40SBenjamin Kramer #else
146399f2f40SBenjamin Kramer     *((size_t*)ptr) = size;
147af0b2207Santirez     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
148399f2f40SBenjamin Kramer     return (char*)ptr+PREFIX_SIZE;
149399f2f40SBenjamin Kramer #endif
150399f2f40SBenjamin Kramer }
151399f2f40SBenjamin Kramer 
zrealloc(void * ptr,size_t size)152e2641e09Santirez void *zrealloc(void *ptr, size_t size) {
153e2641e09Santirez #ifndef HAVE_MALLOC_SIZE
154e2641e09Santirez     void *realptr;
155e2641e09Santirez #endif
156e2641e09Santirez     size_t oldsize;
157e2641e09Santirez     void *newptr;
158e2641e09Santirez 
159e2641e09Santirez     if (ptr == NULL) return zmalloc(size);
160e2641e09Santirez #ifdef HAVE_MALLOC_SIZE
16129d04257Santirez     oldsize = zmalloc_size(ptr);
162e2641e09Santirez     newptr = realloc(ptr,size);
1636fdc6354Santirez     if (!newptr) zmalloc_oom_handler(size);
164e2641e09Santirez 
16567a1810bSantirez     update_zmalloc_stat_free(oldsize);
166af0b2207Santirez     update_zmalloc_stat_alloc(zmalloc_size(newptr));
167e2641e09Santirez     return newptr;
168e2641e09Santirez #else
169e2641e09Santirez     realptr = (char*)ptr-PREFIX_SIZE;
170e2641e09Santirez     oldsize = *((size_t*)realptr);
171e2641e09Santirez     newptr = realloc(realptr,size+PREFIX_SIZE);
1721caa627eSantirez     if (!newptr) zmalloc_oom_handler(size);
173e2641e09Santirez 
174e2641e09Santirez     *((size_t*)newptr) = size;
17567a1810bSantirez     update_zmalloc_stat_free(oldsize);
176af0b2207Santirez     update_zmalloc_stat_alloc(size);
177e2641e09Santirez     return (char*)newptr+PREFIX_SIZE;
178e2641e09Santirez #endif
179e2641e09Santirez }
180e2641e09Santirez 
181442246ddSantirez /* Provide zmalloc_size() for systems where this function is not provided by
18211e81a1eSantirez  * malloc itself, given that in that case we store a header with this
183442246ddSantirez  * information as the first bytes of every allocation. */
184442246ddSantirez #ifndef HAVE_MALLOC_SIZE
zmalloc_size(void * ptr)185442246ddSantirez size_t zmalloc_size(void *ptr) {
186442246ddSantirez     void *realptr = (char*)ptr-PREFIX_SIZE;
187442246ddSantirez     size_t size = *((size_t*)realptr);
188442246ddSantirez     /* Assume at least that all the allocations are padded at sizeof(long) by
189442246ddSantirez      * the underlying allocator. */
190442246ddSantirez     if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
191442246ddSantirez     return size+PREFIX_SIZE;
192442246ddSantirez }
193442246ddSantirez #endif
194442246ddSantirez 
zfree(void * ptr)195e2641e09Santirez void zfree(void *ptr) {
196e2641e09Santirez #ifndef HAVE_MALLOC_SIZE
197e2641e09Santirez     void *realptr;
198e2641e09Santirez     size_t oldsize;
199e2641e09Santirez #endif
200e2641e09Santirez 
201e2641e09Santirez     if (ptr == NULL) return;
202e2641e09Santirez #ifdef HAVE_MALLOC_SIZE
20329d04257Santirez     update_zmalloc_stat_free(zmalloc_size(ptr));
204e2641e09Santirez     free(ptr);
205e2641e09Santirez #else
206e2641e09Santirez     realptr = (char*)ptr-PREFIX_SIZE;
207e2641e09Santirez     oldsize = *((size_t*)realptr);
20867a1810bSantirez     update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
209e2641e09Santirez     free(realptr);
210e2641e09Santirez #endif
211e2641e09Santirez }
212e2641e09Santirez 
zstrdup(const char * s)213e2641e09Santirez char *zstrdup(const char *s) {
214e2641e09Santirez     size_t l = strlen(s)+1;
215e2641e09Santirez     char *p = zmalloc(l);
216e2641e09Santirez 
217e2641e09Santirez     memcpy(p,s,l);
218e2641e09Santirez     return p;
219e2641e09Santirez }
220e2641e09Santirez 
zmalloc_used_memory(void)221e2641e09Santirez size_t zmalloc_used_memory(void) {
222e2641e09Santirez     size_t um;
223e2641e09Santirez 
22480ff1fc6SPremysl Hruby     if (zmalloc_thread_safe) {
225a953c883SMatt Stancliff #if defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC)
226f9bca13aSMatt Stancliff         um = update_zmalloc_stat_add(0);
22780ff1fc6SPremysl Hruby #else
22880ff1fc6SPremysl Hruby         pthread_mutex_lock(&used_memory_mutex);
229e2641e09Santirez         um = used_memory;
23080ff1fc6SPremysl Hruby         pthread_mutex_unlock(&used_memory_mutex);
23180ff1fc6SPremysl Hruby #endif
23280ff1fc6SPremysl Hruby     }
23380ff1fc6SPremysl Hruby     else {
23480ff1fc6SPremysl Hruby         um = used_memory;
23580ff1fc6SPremysl Hruby     }
23680ff1fc6SPremysl Hruby 
237e2641e09Santirez     return um;
238e2641e09Santirez }
239e2641e09Santirez 
zmalloc_enable_thread_safeness(void)240e2641e09Santirez void zmalloc_enable_thread_safeness(void) {
241e2641e09Santirez     zmalloc_thread_safe = 1;
242e2641e09Santirez }
243eddb388eSantirez 
zmalloc_set_oom_handler(void (* oom_handler)(size_t))2446fdc6354Santirez void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
2456fdc6354Santirez     zmalloc_oom_handler = oom_handler;
2466fdc6354Santirez }
2476fdc6354Santirez 
24892e28228Santirez /* Get the RSS information in an OS-specific way.
24992e28228Santirez  *
25092e28228Santirez  * WARNING: the function zmalloc_get_rss() is not designed to be fast
25192e28228Santirez  * and may not be called in the busy loops where Redis tries to release
25292e28228Santirez  * memory expiring or swapping out objects.
25392e28228Santirez  *
25492e28228Santirez  * For this kind of "fast RSS reporting" usages use instead the
25592e28228Santirez  * function RedisEstimateRSS() that is a much faster (and less precise)
2569d09ce39Sguiquanz  * version of the function. */
25773db2accSantirez 
2583cb43283Santirez #if defined(HAVE_PROC_STAT)
25973db2accSantirez #include <unistd.h>
26073db2accSantirez #include <sys/types.h>
26173db2accSantirez #include <sys/stat.h>
26273db2accSantirez #include <fcntl.h>
26373db2accSantirez 
zmalloc_get_rss(void)26492e28228Santirez size_t zmalloc_get_rss(void) {
265eddb388eSantirez     int page = sysconf(_SC_PAGESIZE);
266eddb388eSantirez     size_t rss;
267eddb388eSantirez     char buf[4096];
268eddb388eSantirez     char filename[256];
269eddb388eSantirez     int fd, count;
270eddb388eSantirez     char *p, *x;
271eddb388eSantirez 
272eddb388eSantirez     snprintf(filename,256,"/proc/%d/stat",getpid());
273eddb388eSantirez     if ((fd = open(filename,O_RDONLY)) == -1) return 0;
274eddb388eSantirez     if (read(fd,buf,4096) <= 0) {
275eddb388eSantirez         close(fd);
276eddb388eSantirez         return 0;
277eddb388eSantirez     }
278eddb388eSantirez     close(fd);
279eddb388eSantirez 
280eddb388eSantirez     p = buf;
281eddb388eSantirez     count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
282eddb388eSantirez     while(p && count--) {
283eddb388eSantirez         p = strchr(p,' ');
284eddb388eSantirez         if (p) p++;
285eddb388eSantirez     }
286eddb388eSantirez     if (!p) return 0;
287eddb388eSantirez     x = strchr(p,' ');
288eddb388eSantirez     if (!x) return 0;
289eddb388eSantirez     *x = '\0';
290eddb388eSantirez 
291eddb388eSantirez     rss = strtoll(p,NULL,10);
292eddb388eSantirez     rss *= page;
29392e28228Santirez     return rss;
294eddb388eSantirez }
29573db2accSantirez #elif defined(HAVE_TASKINFO)
29673db2accSantirez #include <unistd.h>
29773db2accSantirez #include <stdio.h>
29873db2accSantirez #include <stdlib.h>
29973db2accSantirez #include <sys/types.h>
30073db2accSantirez #include <sys/sysctl.h>
30173db2accSantirez #include <mach/task.h>
30273db2accSantirez #include <mach/mach_init.h>
30373db2accSantirez 
zmalloc_get_rss(void)30492e28228Santirez size_t zmalloc_get_rss(void) {
30573db2accSantirez     task_t task = MACH_PORT_NULL;
30673db2accSantirez     struct task_basic_info t_info;
30773db2accSantirez     mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
30873db2accSantirez 
30973db2accSantirez     if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
31073db2accSantirez         return 0;
31173db2accSantirez     task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
31273db2accSantirez 
31392e28228Santirez     return t_info.resident_size;
31473db2accSantirez }
31573db2accSantirez #else
zmalloc_get_rss(void)316c4df22afSantirez size_t zmalloc_get_rss(void) {
31792e28228Santirez     /* If we can't get the RSS in an OS-specific way for this system just
31892e28228Santirez      * return the memory usage we estimated in zmalloc()..
31992e28228Santirez      *
32092e28228Santirez      * Fragmentation will appear to be always 1 (no fragmentation)
32192e28228Santirez      * of course... */
32292e28228Santirez     return zmalloc_used_memory();
32373db2accSantirez }
32473db2accSantirez #endif
32592e28228Santirez 
32692e28228Santirez /* Fragmentation = RSS / allocated-bytes */
zmalloc_get_fragmentation_ratio(size_t rss)32793253c27Santirez float zmalloc_get_fragmentation_ratio(size_t rss) {
32893253c27Santirez     return (float)rss/zmalloc_used_memory();
32992e28228Santirez }
3303bfeb9c1Santirez 
3313ef0876bSantirez /* Get the sum of the specified field (converted form kb to bytes) in
3323ef0876bSantirez  * /proc/self/smaps. The field must be specified with trailing ":" as it
3333ef0876bSantirez  * apperas in the smaps output.
3343ef0876bSantirez  *
3353ef0876bSantirez  * Example: zmalloc_get_smap_bytes_by_field("Rss:");
3363ef0876bSantirez  */
3373cb43283Santirez #if defined(HAVE_PROC_SMAPS)
zmalloc_get_smap_bytes_by_field(char * field)3383ef0876bSantirez size_t zmalloc_get_smap_bytes_by_field(char *field) {
3393bfeb9c1Santirez     char line[1024];
3403ef0876bSantirez     size_t bytes = 0;
3413bfeb9c1Santirez     FILE *fp = fopen("/proc/self/smaps","r");
3423ef0876bSantirez     int flen = strlen(field);
3433bfeb9c1Santirez 
3443bfeb9c1Santirez     if (!fp) return 0;
3453bfeb9c1Santirez     while(fgets(line,sizeof(line),fp) != NULL) {
3463ef0876bSantirez         if (strncmp(line,field,flen) == 0) {
3473bfeb9c1Santirez             char *p = strchr(line,'k');
3483bfeb9c1Santirez             if (p) {
3493bfeb9c1Santirez                 *p = '\0';
3503ef0876bSantirez                 bytes += strtol(line+flen,NULL,10) * 1024;
3513bfeb9c1Santirez             }
3523bfeb9c1Santirez         }
3533bfeb9c1Santirez     }
3543bfeb9c1Santirez     fclose(fp);
3553ef0876bSantirez     return bytes;
3563bfeb9c1Santirez }
3573bfeb9c1Santirez #else
zmalloc_get_smap_bytes_by_field(char * field)3583ef0876bSantirez size_t zmalloc_get_smap_bytes_by_field(char *field) {
35962090669Santirez     ((void) field);
3603bfeb9c1Santirez     return 0;
3613bfeb9c1Santirez }
3623bfeb9c1Santirez #endif
3633ef0876bSantirez 
zmalloc_get_private_dirty(void)3643ef0876bSantirez size_t zmalloc_get_private_dirty(void) {
3653ef0876bSantirez     return zmalloc_get_smap_bytes_by_field("Private_Dirty:");
3663ef0876bSantirez }
367615f6923Santirez 
368615f6923Santirez /* Returns the size of physical memory (RAM) in bytes.
369615f6923Santirez  * It looks ugly, but this is the cleanest way to achive cross platform results.
370615f6923Santirez  * Cleaned up from:
371*9a635431Santirez  *
372615f6923Santirez  * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
373*9a635431Santirez  *
374*9a635431Santirez  * Note that this function:
375*9a635431Santirez  * 1) Was released under the following CC attribution license:
376*9a635431Santirez  *    http://creativecommons.org/licenses/by/3.0/deed.en_US.
377*9a635431Santirez  * 2) Was originally implemented by David Robert Nadeau.
378*9a635431Santirez  * 3) Was modified for Redis by Matt Stancliff.
379*9a635431Santirez  * 4) This note exists in order to comply with the original license.
380615f6923Santirez  */
zmalloc_get_memory_size(void)381615f6923Santirez size_t zmalloc_get_memory_size(void) {
382615f6923Santirez #if defined(__unix__) || defined(__unix) || defined(unix) || \
383615f6923Santirez     (defined(__APPLE__) && defined(__MACH__))
384615f6923Santirez #if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
385615f6923Santirez     int mib[2];
386615f6923Santirez     mib[0] = CTL_HW;
387615f6923Santirez #if defined(HW_MEMSIZE)
388615f6923Santirez     mib[1] = HW_MEMSIZE;            /* OSX. --------------------- */
389615f6923Santirez #elif defined(HW_PHYSMEM64)
390615f6923Santirez     mib[1] = HW_PHYSMEM64;          /* NetBSD, OpenBSD. --------- */
391615f6923Santirez #endif
392615f6923Santirez     int64_t size = 0;               /* 64-bit */
393615f6923Santirez     size_t len = sizeof(size);
394615f6923Santirez     if (sysctl( mib, 2, &size, &len, NULL, 0) == 0)
395615f6923Santirez         return (size_t)size;
396615f6923Santirez     return 0L;          /* Failed? */
397615f6923Santirez 
398615f6923Santirez #elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
399615f6923Santirez     /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
400615f6923Santirez     return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE);
401615f6923Santirez 
402615f6923Santirez #elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
403615f6923Santirez     /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
404615f6923Santirez     int mib[2];
405615f6923Santirez     mib[0] = CTL_HW;
406615f6923Santirez #if defined(HW_REALMEM)
407615f6923Santirez     mib[1] = HW_REALMEM;        /* FreeBSD. ----------------- */
408615f6923Santirez #elif defined(HW_PYSMEM)
409615f6923Santirez     mib[1] = HW_PHYSMEM;        /* Others. ------------------ */
410615f6923Santirez #endif
411615f6923Santirez     unsigned int size = 0;      /* 32-bit */
412615f6923Santirez     size_t len = sizeof(size);
413615f6923Santirez     if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
414615f6923Santirez         return (size_t)size;
415615f6923Santirez     return 0L;          /* Failed? */
416615f6923Santirez #endif /* sysctl and sysconf variants */
417615f6923Santirez 
418615f6923Santirez #else
419615f6923Santirez     return 0L;          /* Unknown OS. */
420615f6923Santirez #endif
421615f6923Santirez }
422615f6923Santirez 
423615f6923Santirez 
424