📄 mem3.c
字号:
void *p = memsys3Checkout(mem.iMaster, mem.szMaster); mem.iMaster = 0; mem.szMaster = 0; mem.mnMaster = 0; return p; }else{ /* Split the master block. Return the tail. */ int newi; newi = mem.iMaster + mem.szMaster - nBlock; assert( newi > mem.iMaster+1 ); mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = -nBlock; mem.aPool[newi-1].u.hdr.size = -nBlock; mem.szMaster -= nBlock; mem.aPool[newi-1].u.hdr.prevSize = mem.szMaster; mem.aPool[mem.iMaster-1].u.hdr.size = mem.szMaster; if( mem.szMaster < mem.mnMaster ){ mem.mnMaster = mem.szMaster; } return (void*)&mem.aPool[newi]; }}/*** *pRoot is the head of a list of free chunks of the same size** or same size hash. In other words, *pRoot is an entry in either** mem.aiSmall[] or mem.aiHash[]. **** This routine examines all entries on the given list and tries** to coalesce each entries with adjacent free chunks. **** If it sees a chunk that is larger than mem.iMaster, it replaces ** the current mem.iMaster with the new larger chunk. In order for** this mem.iMaster replacement to work, the master chunk must be** linked into the hash tables. That is not the normal state of** affairs, of course. The calling routine must link the master** chunk before invoking this routine, then must unlink the (possibly** changed) master chunk once this routine has finished.*/static void memsys3Merge(int *pRoot){ int iNext, prev, size, i; assert( sqlite3_mutex_held(mem.mutex) ); for(i=*pRoot; i>0; i=iNext){ iNext = mem.aPool[i].u.list.next; size = mem.aPool[i-1].u.hdr.size; assert( size>0 ); if( mem.aPool[i-1].u.hdr.prevSize>0 ){ memsys3UnlinkFromList(i, pRoot); prev = i - mem.aPool[i-1].u.hdr.prevSize; assert( prev>=0 ); if( prev==iNext ){ iNext = mem.aPool[prev].u.list.next; } memsys3Unlink(prev); size = i + size - prev; mem.aPool[prev-1].u.hdr.size = size; mem.aPool[prev+size-1].u.hdr.prevSize = size; memsys3Link(prev); i = prev; } if( size>mem.szMaster ){ mem.iMaster = i; mem.szMaster = size; } }}/*** Return a block of memory of at least nBytes in size.** Return NULL if unable.*/static void *memsys3Malloc(int nByte){ int i; int nBlock; int toFree; assert( sqlite3_mutex_held(mem.mutex) ); assert( sizeof(Mem3Block)==8 ); if( nByte<=0 ){ nBlock = 2; }else{ nBlock = (nByte + 15)/8; } assert( nBlock >= 2 ); /* STEP 1: ** Look for an entry of the correct size in either the small ** chunk table or in the large chunk hash table. This is ** successful most of the time (about 9 times out of 10). */ if( nBlock <= MX_SMALL ){ i = mem.aiSmall[nBlock-2]; if( i>0 ){ memsys3UnlinkFromList(i, &mem.aiSmall[nBlock-2]); return memsys3Checkout(i, nBlock); } }else{ int hash = nBlock % N_HASH; for(i=mem.aiHash[hash]; i>0; i=mem.aPool[i].u.list.next){ if( mem.aPool[i-1].u.hdr.size==nBlock ){ memsys3UnlinkFromList(i, &mem.aiHash[hash]); return memsys3Checkout(i, nBlock); } } } /* STEP 2: ** Try to satisfy the allocation by carving a piece off of the end ** of the master chunk. This step usually works if step 1 fails. */ if( mem.szMaster>=nBlock ){ return memsys3FromMaster(nBlock); } /* STEP 3: ** Loop through the entire memory pool. Coalesce adjacent free ** chunks. Recompute the master chunk as the largest free chunk. ** Then try again to satisfy the allocation by carving a piece off ** of the end of the master chunk. This step happens very ** rarely (we hope!) */ for(toFree=nBlock*16; toFree<SQLITE_MEMORY_SIZE*2; toFree *= 2){ memsys3OutOfMemory(toFree); if( mem.iMaster ){ memsys3Link(mem.iMaster); mem.iMaster = 0; mem.szMaster = 0; } for(i=0; i<N_HASH; i++){ memsys3Merge(&mem.aiHash[i]); } for(i=0; i<MX_SMALL-1; i++){ memsys3Merge(&mem.aiSmall[i]); } if( mem.szMaster ){ memsys3Unlink(mem.iMaster); if( mem.szMaster>=nBlock ){ return memsys3FromMaster(nBlock); } } } /* If none of the above worked, then we fail. */ return 0;}/*** Free an outstanding memory allocation.*/void memsys3Free(void *pOld){ Mem3Block *p = (Mem3Block*)pOld; int i; int size; assert( sqlite3_mutex_held(mem.mutex) ); assert( p>mem.aPool && p<&mem.aPool[SQLITE_MEMORY_SIZE/8] ); i = p - mem.aPool; size = -mem.aPool[i-1].u.hdr.size; assert( size>=2 ); assert( mem.aPool[i+size-1].u.hdr.prevSize==-size ); mem.aPool[i-1].u.hdr.size = size; mem.aPool[i+size-1].u.hdr.prevSize = size; memsys3Link(i); /* Try to expand the master using the newly freed chunk */ if( mem.iMaster ){ while( mem.aPool[mem.iMaster-1].u.hdr.prevSize>0 ){ size = mem.aPool[mem.iMaster-1].u.hdr.prevSize; mem.iMaster -= size; mem.szMaster += size; memsys3Unlink(mem.iMaster); mem.aPool[mem.iMaster-1].u.hdr.size = mem.szMaster; mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster; } while( mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size>0 ){ memsys3Unlink(mem.iMaster+mem.szMaster); mem.szMaster += mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size; mem.aPool[mem.iMaster-1].u.hdr.size = mem.szMaster; mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster; } }}/*** Allocate nBytes of memory*/void *sqlite3_malloc(int nBytes){ sqlite3_int64 *p = 0; if( nBytes>0 ){ memsys3Enter(); p = memsys3Malloc(nBytes); sqlite3_mutex_leave(mem.mutex); } return (void*)p; }/*** Free memory.*/void sqlite3_free(void *pPrior){ if( pPrior==0 ){ return; } assert( mem.mutex!=0 ); sqlite3_mutex_enter(mem.mutex); memsys3Free(pPrior); sqlite3_mutex_leave(mem.mutex); }/*** Change the size of an existing memory allocation*/void *sqlite3_realloc(void *pPrior, int nBytes){ int nOld; void *p; if( pPrior==0 ){ return sqlite3_malloc(nBytes); } if( nBytes<=0 ){ sqlite3_free(pPrior); return 0; } assert( mem.mutex!=0 ); nOld = memsys3Size(pPrior); if( nBytes<=nOld && nBytes>=nOld-128 ){ return pPrior; } sqlite3_mutex_enter(mem.mutex); p = memsys3Malloc(nBytes); if( p ){ if( nOld<nBytes ){ memcpy(p, pPrior, nOld); }else{ memcpy(p, pPrior, nBytes); } memsys3Free(pPrior); } sqlite3_mutex_leave(mem.mutex); return p;}/*** Open the file indicated and write a log of all unfreed memory ** allocations into that log.*/void sqlite3_memdebug_dump(const char *zFilename){#ifdef SQLITE_DEBUG FILE *out; int i, j, size; if( zFilename==0 || zFilename[0]==0 ){ out = stdout; }else{ out = fopen(zFilename, "w"); if( out==0 ){ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", zFilename); return; } } memsys3Enter(); fprintf(out, "CHUNKS:\n"); for(i=1; i<=SQLITE_MEMORY_SIZE/8; i+=size){ size = mem.aPool[i-1].u.hdr.size; if( size>=-1 && size<=1 ){ fprintf(out, "%p size error\n", &mem.aPool[i]); assert( 0 ); break; } if( mem.aPool[i+(size<0?-size:size)-1].u.hdr.prevSize!=size ){ fprintf(out, "%p tail size does not match\n", &mem.aPool[i]); assert( 0 ); break; } if( size<0 ){ size = -size; fprintf(out, "%p %6d bytes checked out\n", &mem.aPool[i], size*8-8); }else{ fprintf(out, "%p %6d bytes free%s\n", &mem.aPool[i], size*8-8, i==mem.iMaster ? " **master**" : ""); } } for(i=0; i<MX_SMALL-1; i++){ if( mem.aiSmall[i]==0 ) continue; fprintf(out, "small(%2d):", i); for(j = mem.aiSmall[i]; j>0; j=mem.aPool[j].u.list.next){ fprintf(out, " %p(%d)", &mem.aPool[j], mem.aPool[j-1].u.hdr.size*8-8); } fprintf(out, "\n"); } for(i=0; i<N_HASH; i++){ if( mem.aiHash[i]==0 ) continue; fprintf(out, "hash(%2d):", i); for(j = mem.aiHash[i]; j>0; j=mem.aPool[j].u.list.next){ fprintf(out, " %p(%d)", &mem.aPool[j], mem.aPool[j-1].u.hdr.size*8-8); } fprintf(out, "\n"); } fprintf(out, "master=%d\n", mem.iMaster); fprintf(out, "nowUsed=%d\n", SQLITE_MEMORY_SIZE - mem.szMaster*8); fprintf(out, "mxUsed=%d\n", SQLITE_MEMORY_SIZE - mem.mnMaster*8); sqlite3_mutex_leave(mem.mutex); if( out==stdout ){ fflush(stdout); }else{ fclose(out); }#endif}#endif /* !SQLITE_MEMORY_SIZE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -