📄 ut0mem.c
字号:
/************************************************************************Memory primitives(c) 1994, 1995 Innobase OyCreated 5/11/1994 Heikki Tuuri*************************************************************************/#include "ut0mem.h"#ifdef UNIV_NONINL#include "ut0mem.ic"#endif#include "mem0mem.h"#include "os0sync.h"#include "os0thread.h"/* This struct is placed first in every allocated memory block */typedef struct ut_mem_block_struct ut_mem_block_t;/* The total amount of memory currently allocated from the OS with malloc */ulint ut_total_allocated_memory = 0;struct ut_mem_block_struct{ UT_LIST_NODE_T(ut_mem_block_t) mem_block_list; /* mem block list node */ ulint size; /* size of allocated memory */ ulint magic_n;};#define UT_MEM_MAGIC_N 1601650166/* List of all memory blocks allocated from the operating systemwith malloc */UT_LIST_BASE_NODE_T(ut_mem_block_t) ut_mem_block_list;os_fast_mutex_t ut_list_mutex; /* this protects the list */ibool ut_mem_block_list_inited = FALSE;ulint* ut_mem_null_ptr = NULL;/**************************************************************************Initializes the mem block list at database startup. */staticvoidut_mem_block_list_init(void)/*========================*/{ os_fast_mutex_init(&ut_list_mutex); UT_LIST_INIT(ut_mem_block_list); ut_mem_block_list_inited = TRUE;}/**************************************************************************Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO isdefined and set_to_zero is TRUE. */void*ut_malloc_low(/*==========*/ /* out, own: allocated memory */ ulint n, /* in: number of bytes to allocate */ ibool set_to_zero, /* in: TRUE if allocated memory should be set to zero if UNIV_SET_MEM_TO_ZERO is defined */ ibool assert_on_error) /* in: if TRUE, we crash mysqld if the memory cannot be allocated */{ ulint retry_count = 0; void* ret; ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */ if (!ut_mem_block_list_inited) { ut_mem_block_list_init(); }retry: os_fast_mutex_lock(&ut_list_mutex); ret = malloc(n + sizeof(ut_mem_block_t)); if (ret == NULL && retry_count < 60) { if (retry_count == 0) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Error: cannot allocate %lu bytes of\n" "InnoDB: memory with malloc! Total allocated memory\n" "InnoDB: by InnoDB %lu bytes. Operating system errno: %lu\n" "InnoDB: Check if you should increase the swap file or\n" "InnoDB: ulimits of your operating system.\n" "InnoDB: On FreeBSD check you have compiled the OS with\n" "InnoDB: a big enough maximum process size.\n" "InnoDB: Note that in most 32-bit computers the process\n" "InnoDB: memory space is limited to 2 GB or 4 GB.\n" "InnoDB: We keep retrying the allocation for 60 seconds...\n", (ulong) n, (ulong) ut_total_allocated_memory,#ifdef __WIN__ (ulong) GetLastError()#else (ulong) errno#endif ); } os_fast_mutex_unlock(&ut_list_mutex); /* Sleep for a second and retry the allocation; maybe this is just a temporary shortage of memory */ os_thread_sleep(1000000); retry_count++; goto retry; } if (ret == NULL) { /* Flush stderr to make more probable that the error message gets in the error file before we generate a seg fault */ fflush(stderr); os_fast_mutex_unlock(&ut_list_mutex); /* Make an intentional seg fault so that we get a stack trace */ /* Intentional segfault on NetWare causes an abend. Avoid this by graceful exit handling in ut_a(). */#if (!defined __NETWARE__) if (assert_on_error) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: We now intentionally generate a seg fault so that\n" "InnoDB: on Linux we get a stack trace.\n"); if (*ut_mem_null_ptr) ut_mem_null_ptr = 0; } else { return(NULL); }#else ut_a(0);#endif } if (set_to_zero) {#ifdef UNIV_SET_MEM_TO_ZERO memset(ret, '\0', n + sizeof(ut_mem_block_t));#endif } ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t); ((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N; ut_total_allocated_memory += n + sizeof(ut_mem_block_t); UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list, ((ut_mem_block_t*)ret)); os_fast_mutex_unlock(&ut_list_mutex); return((void*)((byte*)ret + sizeof(ut_mem_block_t)));}/**************************************************************************Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO isdefined. */void*ut_malloc(/*======*/ /* out, own: allocated memory */ ulint n) /* in: number of bytes to allocate */{ return(ut_malloc_low(n, TRUE, TRUE));}/**************************************************************************Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runsout. It cannot be used if we want to return an error message. Prints tostderr a message if fails. */iboolut_test_malloc(/*===========*/ /* out: TRUE if succeeded */ ulint n) /* in: try to allocate this many bytes */{ void* ret; ret = malloc(n); if (ret == NULL) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Error: cannot allocate %lu bytes of memory for\n" "InnoDB: a BLOB with malloc! Total allocated memory\n" "InnoDB: by InnoDB %lu bytes. Operating system errno: %d\n" "InnoDB: Check if you should increase the swap file or\n" "InnoDB: ulimits of your operating system.\n" "InnoDB: On FreeBSD check you have compiled the OS with\n" "InnoDB: a big enough maximum process size.\n", (ulong) n, (ulong) ut_total_allocated_memory, (int) errno); return(FALSE); } free(ret); return(TRUE);} /**************************************************************************Frees a memory block allocated with ut_malloc. */voidut_free(/*====*/ void* ptr) /* in, own: memory block */{ ut_mem_block_t* block; block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t)); os_fast_mutex_lock(&ut_list_mutex); ut_a(block->magic_n == UT_MEM_MAGIC_N); ut_a(ut_total_allocated_memory >= block->size); ut_total_allocated_memory -= block->size; UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block); free(block); os_fast_mutex_unlock(&ut_list_mutex);}/**************************************************************************Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should notuse this function because the allocation functions in mem0mem.h are therecommended ones in InnoDB.man realloc in Linux, 2004: realloc() changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated mem
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -