📄 mem2.c
字号:
/*** 2007 August 15**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.***************************************************************************** This file contains the C functions that implement a memory** allocation subsystem for use by SQLite. **** $Id: mem2.c,v 1.18 2007/11/29 18:36:49 drh Exp $*//*** This version of the memory allocator is used only if the** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION** is not defined.*/#if defined(SQLITE_MEMDEBUG)/*** We will eventually construct multiple memory allocation subsystems** suitable for use in various contexts:**** * Normal multi-threaded builds** * Normal single-threaded builds** * Debugging builds**** This version is suitable for use in debugging builds.**** Features:**** * Every allocate has guards at both ends.** * New allocations are initialized with randomness** * Allocations are overwritten with randomness when freed** * Optional logs of malloc activity generated** * Summary of outstanding allocations with backtraces to the** point of allocation.** * The ability to simulate memory allocation failure*/#include "sqliteInt.h"#include <stdio.h>/*** The backtrace functionality is only available with GLIBC*/#ifdef __GLIBC__ extern int backtrace(void**,int); extern void backtrace_symbols_fd(void*const*,int,int);#else# define backtrace(A,B) 0# define backtrace_symbols_fd(A,B,C)#endif/*** Each memory allocation looks like this:**** ------------------------------------------------------------------------** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard |** ------------------------------------------------------------------------**** The application code sees only a pointer to the allocation. We have** to back up from the allocation pointer to find the MemBlockHdr. The** MemBlockHdr tells us the size of the allocation and the number of** backtrace pointers. There is also a guard word at the end of the** MemBlockHdr.*/struct MemBlockHdr { struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ int iSize; /* Size of this allocation */ char nBacktrace; /* Number of backtraces on this alloc */ char nBacktraceSlots; /* Available backtrace slots */ short nTitle; /* Bytes of title; includes '\0' */ int iForeGuard; /* Guard word for sanity */};/*** Guard words*/#define FOREGUARD 0x80F5E153#define REARGUARD 0xE4676B53/*** Number of malloc size increments to track.*/#define NCSIZE 1000/*** All of the static variables used by this module are collected** into a single structure named "mem". This is to keep the** static variables organized and to reduce namespace pollution** when this module is combined with other in the amalgamation.*/static struct { /* ** The alarm callback and its arguments. The mem.mutex lock will ** be held while the callback is running. Recursive calls into ** the memory subsystem are allowed, but no new callbacks will be ** issued. The alarmBusy variable is set to prevent recursive ** callbacks. */ sqlite3_int64 alarmThreshold; void (*alarmCallback)(void*, sqlite3_int64, int); void *alarmArg; int alarmBusy; /* ** Mutex to control access to the memory allocation subsystem. */ sqlite3_mutex *mutex; /* ** Current allocation and high-water mark. */ sqlite3_int64 nowUsed; sqlite3_int64 mxUsed; /* ** Head and tail of a linked list of all outstanding allocations */ struct MemBlockHdr *pFirst; struct MemBlockHdr *pLast; /* ** The number of levels of backtrace to save in new allocations. */ int nBacktrace; /* ** Title text to insert in front of each block */ int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ char zTitle[100]; /* The title text */ /* ** These values are used to simulate malloc failures. When ** iFail is 1, simulate a malloc failures and reset the value ** to iReset. */ int iFail; /* Decrement and fail malloc when this is 1 */ int iReset; /* When malloc fails set iiFail to this value */ int iFailCnt; /* Number of failures */ int iBenignFailCnt; /* Number of benign failures */ int iNextIsBenign; /* True if the next call to malloc may fail benignly */ int iIsBenign; /* All malloc calls may fail benignly */ /* ** sqlite3MallocDisallow() increments the following counter. ** sqlite3MallocAllow() decrements it. */ int disallow; /* Do not allow memory allocation */ /* ** Gather statistics on the sizes of memory allocations. ** sizeCnt[i] is the number of allocation attempts of i*8 ** bytes. i==NCSIZE is the number of allocation attempts for ** sizes more than NCSIZE*8 bytes. */ int sizeCnt[NCSIZE];} mem;/*** Enter the mutex mem.mutex. Allocate it if it is not already allocated.*/static void enterMem(void){ if( mem.mutex==0 ){ mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); } sqlite3_mutex_enter(mem.mutex);}/*** Return the amount of memory currently checked out.*/sqlite3_int64 sqlite3_memory_used(void){ sqlite3_int64 n; enterMem(); n = mem.nowUsed; sqlite3_mutex_leave(mem.mutex); return n;}/*** Return the maximum amount of memory that has ever been** checked out since either the beginning of this process** or since the most recent reset.*/sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ sqlite3_int64 n; enterMem(); n = mem.mxUsed; if( resetFlag ){ mem.mxUsed = mem.nowUsed; } sqlite3_mutex_leave(mem.mutex); return n;}/*** Change the alarm callback*/int sqlite3_memory_alarm( void(*xCallback)(void *pArg, sqlite3_int64 used, int N), void *pArg, sqlite3_int64 iThreshold){ enterMem(); mem.alarmCallback = xCallback; mem.alarmArg = pArg; mem.alarmThreshold = iThreshold; sqlite3_mutex_leave(mem.mutex); return SQLITE_OK;}/*** Trigger the alarm */static void sqlite3MemsysAlarm(int nByte){ void (*xCallback)(void*,sqlite3_int64,int); sqlite3_int64 nowUsed; void *pArg; if( mem.alarmCallback==0 || mem.alarmBusy ) return; mem.alarmBusy = 1; xCallback = mem.alarmCallback; nowUsed = mem.nowUsed; pArg = mem.alarmArg; sqlite3_mutex_leave(mem.mutex); xCallback(pArg, nowUsed, nByte); sqlite3_mutex_enter(mem.mutex); mem.alarmBusy = 0;}/*** Given an allocation, find the MemBlockHdr for that allocation.**** This routine checks the guards at either end of the allocation and** if they are incorrect it asserts.*/static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ struct MemBlockHdr *p; int *pInt; p = (struct MemBlockHdr*)pAllocation; p--; assert( p->iForeGuard==FOREGUARD ); assert( (p->iSize & 3)==0 ); pInt = (int*)pAllocation; assert( pInt[p->iSize/sizeof(int)]==REARGUARD ); return p;}/*** This routine is called once the first time a simulated memory** failure occurs. The sole purpose of this routine is to provide** a convenient place to set a debugger breakpoint when debugging** errors related to malloc() failures.*/static void sqlite3MemsysFailed(void){ mem.iFailCnt = 0; mem.iBenignFailCnt = 0;}/*** Allocate nByte bytes of memory.*/void *sqlite3_malloc(int nByte){ struct MemBlockHdr *pHdr; void **pBt; char *z; int *pInt; void *p = 0; int totalSize; if( nByte>0 ){ enterMem(); assert( mem.disallow==0 ); if( mem.alarmCallback!=0 && mem.nowUsed+nByte>=mem.alarmThreshold ){ sqlite3MemsysAlarm(nByte); } nByte = (nByte+3)&~3; if( nByte/8>NCSIZE-1 ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -