mirror of
https://github.com/fluencelabs/redis
synced 2025-03-26 20:31:03 +00:00
calloc is more effecient than malloc+memset when the system uses mmap to allocate memory. mmap always returns zeroed memory so the memset can be avoided. The threshold to use mmap is 16k in osx libc and 128k in bsd libc and glibc. The kernel can lazily allocate the pages, this reduces memory usage when we have a page table or hash table that is mostly empty. This change is most visible when you start a new redis instance with vm enabled. You'll see no increased memory usage no matter how big your page table is.
173 lines
5.0 KiB
C
173 lines
5.0 KiB
C
/* zmalloc - total amount of allocated memory aware version of malloc()
|
|
*
|
|
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of Redis nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include "config.h"
|
|
|
|
#if defined(__sun)
|
|
#define PREFIX_SIZE sizeof(long long)
|
|
#else
|
|
#define PREFIX_SIZE sizeof(size_t)
|
|
#endif
|
|
|
|
#define increment_used_memory(__n) do { \
|
|
size_t _n = (__n); \
|
|
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
|
|
if (zmalloc_thread_safe) { \
|
|
pthread_mutex_lock(&used_memory_mutex); \
|
|
used_memory += _n; \
|
|
pthread_mutex_unlock(&used_memory_mutex); \
|
|
} else { \
|
|
used_memory += _n; \
|
|
} \
|
|
} while(0)
|
|
|
|
#define decrement_used_memory(__n) do { \
|
|
size_t _n = (__n); \
|
|
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
|
|
if (zmalloc_thread_safe) { \
|
|
pthread_mutex_lock(&used_memory_mutex); \
|
|
used_memory -= _n; \
|
|
pthread_mutex_unlock(&used_memory_mutex); \
|
|
} else { \
|
|
used_memory -= _n; \
|
|
} \
|
|
} while(0)
|
|
|
|
static size_t used_memory = 0;
|
|
static int zmalloc_thread_safe = 0;
|
|
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static void zmalloc_oom(size_t size) {
|
|
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
|
|
size);
|
|
fflush(stderr);
|
|
abort();
|
|
}
|
|
|
|
void *zmalloc(size_t size) {
|
|
void *ptr = malloc(size+PREFIX_SIZE);
|
|
|
|
if (!ptr) zmalloc_oom(size);
|
|
#ifdef HAVE_MALLOC_SIZE
|
|
increment_used_memory(redis_malloc_size(ptr));
|
|
return ptr;
|
|
#else
|
|
*((size_t*)ptr) = size;
|
|
increment_used_memory(size+PREFIX_SIZE);
|
|
return (char*)ptr+PREFIX_SIZE;
|
|
#endif
|
|
}
|
|
|
|
void *zcalloc(size_t size) {
|
|
void *ptr = calloc(1, size+PREFIX_SIZE);
|
|
|
|
if (!ptr) zmalloc_oom(size);
|
|
#ifdef HAVE_MALLOC_SIZE
|
|
increment_used_memory(redis_malloc_size(ptr));
|
|
return ptr;
|
|
#else
|
|
*((size_t*)ptr) = size;
|
|
increment_used_memory(size+PREFIX_SIZE);
|
|
return (char*)ptr+PREFIX_SIZE;
|
|
#endif
|
|
}
|
|
|
|
void *zrealloc(void *ptr, size_t size) {
|
|
#ifndef HAVE_MALLOC_SIZE
|
|
void *realptr;
|
|
#endif
|
|
size_t oldsize;
|
|
void *newptr;
|
|
|
|
if (ptr == NULL) return zmalloc(size);
|
|
#ifdef HAVE_MALLOC_SIZE
|
|
oldsize = redis_malloc_size(ptr);
|
|
newptr = realloc(ptr,size);
|
|
if (!newptr) zmalloc_oom(size);
|
|
|
|
decrement_used_memory(oldsize);
|
|
increment_used_memory(redis_malloc_size(newptr));
|
|
return newptr;
|
|
#else
|
|
realptr = (char*)ptr-PREFIX_SIZE;
|
|
oldsize = *((size_t*)realptr);
|
|
newptr = realloc(realptr,size+PREFIX_SIZE);
|
|
if (!newptr) zmalloc_oom(size);
|
|
|
|
*((size_t*)newptr) = size;
|
|
decrement_used_memory(oldsize);
|
|
increment_used_memory(size);
|
|
return (char*)newptr+PREFIX_SIZE;
|
|
#endif
|
|
}
|
|
|
|
void zfree(void *ptr) {
|
|
#ifndef HAVE_MALLOC_SIZE
|
|
void *realptr;
|
|
size_t oldsize;
|
|
#endif
|
|
|
|
if (ptr == NULL) return;
|
|
#ifdef HAVE_MALLOC_SIZE
|
|
decrement_used_memory(redis_malloc_size(ptr));
|
|
free(ptr);
|
|
#else
|
|
realptr = (char*)ptr-PREFIX_SIZE;
|
|
oldsize = *((size_t*)realptr);
|
|
decrement_used_memory(oldsize+PREFIX_SIZE);
|
|
free(realptr);
|
|
#endif
|
|
}
|
|
|
|
char *zstrdup(const char *s) {
|
|
size_t l = strlen(s)+1;
|
|
char *p = zmalloc(l);
|
|
|
|
memcpy(p,s,l);
|
|
return p;
|
|
}
|
|
|
|
size_t zmalloc_used_memory(void) {
|
|
size_t um;
|
|
|
|
if (zmalloc_thread_safe) pthread_mutex_lock(&used_memory_mutex);
|
|
um = used_memory;
|
|
if (zmalloc_thread_safe) pthread_mutex_unlock(&used_memory_mutex);
|
|
return um;
|
|
}
|
|
|
|
void zmalloc_enable_thread_safeness(void) {
|
|
zmalloc_thread_safe = 1;
|
|
}
|