1 /* 2 ** 2007 October 14 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** This file contains the C functions that implement a memory 13 ** allocation subsystem for use by SQLite. 14 ** 15 ** This version of the memory allocation subsystem omits all 16 ** use of malloc(). All dynamically allocatable memory is 17 ** contained in a static array, mem.aPool[]. The size of this 18 ** fixed memory pool is SQLITE_MEMORY_SIZE bytes. 19 ** 20 ** This version of the memory allocation subsystem is used if 21 ** and only if SQLITE_MEMORY_SIZE is defined. 22 ** 23 ** $Id: mem3.c,v 1.12 2008/02/19 15:15:16 drh Exp $ 24 */ 25 #include "sqliteInt.h" 26 27 /* 28 ** This version of the memory allocator is used only when 29 ** SQLITE_MEMORY_SIZE is defined. 30 */ 31 #ifdef SQLITE_MEMORY_SIZE 32 33 /* 34 ** Maximum size (in Mem3Blocks) of a "small" chunk. 35 */ 36 #define MX_SMALL 10 37 38 39 /* 40 ** Number of freelist hash slots 41 */ 42 #define N_HASH 61 43 44 /* 45 ** A memory allocation (also called a "chunk") consists of two or 46 ** more blocks where each block is 8 bytes. The first 8 bytes are 47 ** a header that is not returned to the user. 48 ** 49 ** A chunk is two or more blocks that is either checked out or 50 ** free. The first block has format u.hdr. u.hdr.size4x is 4 times the 51 ** size of the allocation in blocks if the allocation is free. 52 ** The u.hdr.size4x&1 bit is true if the chunk is checked out and 53 ** false if the chunk is on the freelist. The u.hdr.size4x&2 bit 54 ** is true if the previous chunk is checked out and false if the 55 ** previous chunk is free. The u.hdr.prevSize field is the size of 56 ** the previous chunk in blocks if the previous chunk is on the 57 ** freelist. If the previous chunk is checked out, then 58 ** u.hdr.prevSize can be part of the data for that chunk and should 59 ** not be read or written. 60 ** 61 ** We often identify a chunk by its index in mem.aPool[]. When 62 ** this is done, the chunk index refers to the second block of 63 ** the chunk. In this way, the first chunk has an index of 1. 64 ** A chunk index of 0 means "no such chunk" and is the equivalent 65 ** of a NULL pointer. 66 ** 67 ** The second block of free chunks is of the form u.list. The 68 ** two fields form a double-linked list of chunks of related sizes. 69 ** Pointers to the head of the list are stored in mem.aiSmall[] 70 ** for smaller chunks and mem.aiHash[] for larger chunks. 71 ** 72 ** The second block of a chunk is user data if the chunk is checked 73 ** out. If a chunk is checked out, the user data may extend into 74 ** the u.hdr.prevSize value of the following chunk. 75 */ 76 typedef struct Mem3Block Mem3Block; 77 struct Mem3Block { 78 union { 79 struct { 80 u32 prevSize; /* Size of previous chunk in Mem3Block elements */ 81 u32 size4x; /* 4x the size of current chunk in Mem3Block elements */ 82 } hdr; 83 struct { 84 u32 next; /* Index in mem.aPool[] of next free chunk */ 85 u32 prev; /* Index in mem.aPool[] of previous free chunk */ 86 } list; 87 } u; 88 }; 89 90 /* 91 ** All of the static variables used by this module are collected 92 ** into a single structure named "mem". This is to keep the 93 ** static variables organized and to reduce namespace pollution 94 ** when this module is combined with other in the amalgamation. 95 */ 96 static struct { 97 /* 98 ** True if we are evaluating an out-of-memory callback. 99 */ 100 int alarmBusy; 101 102 /* 103 ** Mutex to control access to the memory allocation subsystem. 104 */ 105 sqlite3_mutex *mutex; 106 107 /* 108 ** The minimum amount of free space that we have seen. 109 */ 110 u32 mnMaster; 111 112 /* 113 ** iMaster is the index of the master chunk. Most new allocations 114 ** occur off of this chunk. szMaster is the size (in Mem3Blocks) 115 ** of the current master. iMaster is 0 if there is not master chunk. 116 ** The master chunk is not in either the aiHash[] or aiSmall[]. 117 */ 118 u32 iMaster; 119 u32 szMaster; 120 121 /* 122 ** Array of lists of free blocks according to the block size 123 ** for smaller chunks, or a hash on the block size for larger 124 ** chunks. 125 */ 126 u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */ 127 u32 aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */ 128 129 /* 130 ** Memory available for allocation 131 */ 132 Mem3Block aPool[SQLITE_MEMORY_SIZE/sizeof(Mem3Block)+2]; 133 } mem; 134 135 /* 136 ** Unlink the chunk at mem.aPool[i] from list it is currently 137 ** on. *pRoot is the list that i is a member of. 138 */ 139 static void memsys3UnlinkFromList(u32 i, u32 *pRoot){ 140 u32 next = mem.aPool[i].u.list.next; 141 u32 prev = mem.aPool[i].u.list.prev; 142 assert( sqlite3_mutex_held(mem.mutex) ); 143 if( prev==0 ){ 144 *pRoot = next; 145 }else{ 146 mem.aPool[prev].u.list.next = next; 147 } 148 if( next ){ 149 mem.aPool[next].u.list.prev = prev; 150 } 151 mem.aPool[i].u.list.next = 0; 152 mem.aPool[i].u.list.prev = 0; 153 } 154 155 /* 156 ** Unlink the chunk at index i from 157 ** whatever list is currently a member of. 158 */ 159 static void memsys3Unlink(u32 i){ 160 u32 size, hash; 161 assert( sqlite3_mutex_held(mem.mutex) ); 162 assert( (mem.aPool[i-1].u.hdr.size4x & 1)==0 ); 163 assert( i>=1 ); 164 size = mem.aPool[i-1].u.hdr.size4x/4; 165 assert( size==mem.aPool[i+size-1].u.hdr.prevSize ); 166 assert( size>=2 ); 167 if( size <= MX_SMALL ){ 168 memsys3UnlinkFromList(i, &mem.aiSmall[size-2]); 169 }else{ 170 hash = size % N_HASH; 171 memsys3UnlinkFromList(i, &mem.aiHash[hash]); 172 } 173 } 174 175 /* 176 ** Link the chunk at mem.aPool[i] so that is on the list rooted 177 ** at *pRoot. 178 */ 179 static void memsys3LinkIntoList(u32 i, u32 *pRoot){ 180 assert( sqlite3_mutex_held(mem.mutex) ); 181 mem.aPool[i].u.list.next = *pRoot; 182 mem.aPool[i].u.list.prev = 0; 183 if( *pRoot ){ 184 mem.aPool[*pRoot].u.list.prev = i; 185 } 186 *pRoot = i; 187 } 188 189 /* 190 ** Link the chunk at index i into either the appropriate 191 ** small chunk list, or into the large chunk hash table. 192 */ 193 static void memsys3Link(u32 i){ 194 u32 size, hash; 195 assert( sqlite3_mutex_held(mem.mutex) ); 196 assert( i>=1 ); 197 assert( (mem.aPool[i-1].u.hdr.size4x & 1)==0 ); 198 size = mem.aPool[i-1].u.hdr.size4x/4; 199 assert( size==mem.aPool[i+size-1].u.hdr.prevSize ); 200 assert( size>=2 ); 201 if( size <= MX_SMALL ){ 202 memsys3LinkIntoList(i, &mem.aiSmall[size-2]); 203 }else{ 204 hash = size % N_HASH; 205 memsys3LinkIntoList(i, &mem.aiHash[hash]); 206 } 207 } 208 209 /* 210 ** Enter the mutex mem.mutex. Allocate it if it is not already allocated. 211 ** 212 ** Also: Initialize the memory allocation subsystem the first time 213 ** this routine is called. 214 */ 215 static void memsys3Enter(void){ 216 if( mem.mutex==0 ){ 217 mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); 218 mem.aPool[0].u.hdr.size4x = SQLITE_MEMORY_SIZE/2 + 2; 219 mem.aPool[SQLITE_MEMORY_SIZE/8].u.hdr.prevSize = SQLITE_MEMORY_SIZE/8; 220 mem.aPool[SQLITE_MEMORY_SIZE/8].u.hdr.size4x = 1; 221 mem.iMaster = 1; 222 mem.szMaster = SQLITE_MEMORY_SIZE/8; 223 mem.mnMaster = mem.szMaster; 224 } 225 sqlite3_mutex_enter(mem.mutex); 226 } 227 228 /* 229 ** Return the amount of memory currently checked out. 230 */ 231 sqlite3_int64 sqlite3_memory_used(void){ 232 sqlite3_int64 n; 233 memsys3Enter(); 234 n = SQLITE_MEMORY_SIZE - mem.szMaster*8; 235 sqlite3_mutex_leave(mem.mutex); 236 return n; 237 } 238 239 /* 240 ** Return the maximum amount of memory that has ever been 241 ** checked out since either the beginning of this process 242 ** or since the most recent reset. 243 */ 244 sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ 245 sqlite3_int64 n; 246 memsys3Enter(); 247 n = SQLITE_MEMORY_SIZE - mem.mnMaster*8; 248 if( resetFlag ){ 249 mem.mnMaster = mem.szMaster; 250 } 251 sqlite3_mutex_leave(mem.mutex); 252 return n; 253 } 254 255 /* 256 ** Change the alarm callback. 257 ** 258 ** This is a no-op for the static memory allocator. The purpose 259 ** of the memory alarm is to support sqlite3_soft_heap_limit(). 260 ** But with this memory allocator, the soft_heap_limit is really 261 ** a hard limit that is fixed at SQLITE_MEMORY_SIZE. 262 */ 263 int sqlite3_memory_alarm( 264 void(*xCallback)(void *pArg, sqlite3_int64 used,int N), 265 void *pArg, 266 sqlite3_int64 iThreshold 267 ){ 268 return SQLITE_OK; 269 } 270 271 /* 272 ** Called when we are unable to satisfy an allocation of nBytes. 273 */ 274 static void memsys3OutOfMemory(int nByte){ 275 if( !mem.alarmBusy ){ 276 mem.alarmBusy = 1; 277 assert( sqlite3_mutex_held(mem.mutex) ); 278 sqlite3_mutex_leave(mem.mutex); 279 sqlite3_release_memory(nByte); 280 sqlite3_mutex_enter(mem.mutex); 281 mem.alarmBusy = 0; 282 } 283 } 284 285 /* 286 ** Return the size of an outstanding allocation, in bytes. The 287 ** size returned omits the 8-byte header overhead. This only 288 ** works for chunks that are currently checked out. 289 */ 290 int sqlite3MallocSize(void *p){ 291 int iSize = 0; 292 if( p ){ 293 Mem3Block *pBlock = (Mem3Block*)p; 294 assert( (pBlock[-1].u.hdr.size4x&1)!=0 ); 295 iSize = (pBlock[-1].u.hdr.size4x&~3)*2 - 4; 296 } 297 return iSize; 298 } 299 300 /* 301 ** Chunk i is a free chunk that has been unlinked. Adjust its 302 ** size parameters for check-out and return a pointer to the 303 ** user portion of the chunk. 304 */ 305 static void *memsys3Checkout(u32 i, int nBlock){ 306 u32 x; 307 assert( sqlite3_mutex_held(mem.mutex) ); 308 assert( i>=1 ); 309 assert( mem.aPool[i-1].u.hdr.size4x/4==nBlock ); 310 assert( mem.aPool[i+nBlock-1].u.hdr.prevSize==nBlock ); 311 x = mem.aPool[i-1].u.hdr.size4x; 312 mem.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); 313 mem.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; 314 mem.aPool[i+nBlock-1].u.hdr.size4x |= 2; 315 return &mem.aPool[i]; 316 } 317 318 /* 319 ** Carve a piece off of the end of the mem.iMaster free chunk. 320 ** Return a pointer to the new allocation. Or, if the master chunk 321 ** is not large enough, return 0. 322 */ 323 static void *memsys3FromMaster(int nBlock){ 324 assert( sqlite3_mutex_held(mem.mutex) ); 325 assert( mem.szMaster>=nBlock ); 326 if( nBlock>=mem.szMaster-1 ){ 327 /* Use the entire master */ 328 void *p = memsys3Checkout(mem.iMaster, mem.szMaster); 329 mem.iMaster = 0; 330 mem.szMaster = 0; 331 mem.mnMaster = 0; 332 return p; 333 }else{ 334 /* Split the master block. Return the tail. */ 335 u32 newi, x; 336 newi = mem.iMaster + mem.szMaster - nBlock; 337 assert( newi > mem.iMaster+1 ); 338 mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = nBlock; 339 mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size4x |= 2; 340 mem.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; 341 mem.szMaster -= nBlock; 342 mem.aPool[newi-1].u.hdr.prevSize = mem.szMaster; 343 x = mem.aPool[mem.iMaster-1].u.hdr.size4x & 2; 344 mem.aPool[mem.iMaster-1].u.hdr.size4x = mem.szMaster*4 | x; 345 if( mem.szMaster < mem.mnMaster ){ 346 mem.mnMaster = mem.szMaster; 347 } 348 return (void*)&mem.aPool[newi]; 349 } 350 } 351 352 /* 353 ** *pRoot is the head of a list of free chunks of the same size 354 ** or same size hash. In other words, *pRoot is an entry in either 355 ** mem.aiSmall[] or mem.aiHash[]. 356 ** 357 ** This routine examines all entries on the given list and tries 358 ** to coalesce each entries with adjacent free chunks. 359 ** 360 ** If it sees a chunk that is larger than mem.iMaster, it replaces 361 ** the current mem.iMaster with the new larger chunk. In order for 362 ** this mem.iMaster replacement to work, the master chunk must be 363 ** linked into the hash tables. That is not the normal state of 364 ** affairs, of course. The calling routine must link the master 365 ** chunk before invoking this routine, then must unlink the (possibly 366 ** changed) master chunk once this routine has finished. 367 */ 368 static void memsys3Merge(u32 *pRoot){ 369 u32 iNext, prev, size, i, x; 370 371 assert( sqlite3_mutex_held(mem.mutex) ); 372 for(i=*pRoot; i>0; i=iNext){ 373 iNext = mem.aPool[i].u.list.next; 374 size = mem.aPool[i-1].u.hdr.size4x; 375 assert( (size&1)==0 ); 376 if( (size&2)==0 ){ 377 memsys3UnlinkFromList(i, pRoot); 378 assert( i > mem.aPool[i-1].u.hdr.prevSize ); 379 prev = i - mem.aPool[i-1].u.hdr.prevSize; 380 if( prev==iNext ){ 381 iNext = mem.aPool[prev].u.list.next; 382 } 383 memsys3Unlink(prev); 384 size = i + size/4 - prev; 385 x = mem.aPool[prev-1].u.hdr.size4x & 2; 386 mem.aPool[prev-1].u.hdr.size4x = size*4 | x; 387 mem.aPool[prev+size-1].u.hdr.prevSize = size; 388 memsys3Link(prev); 389 i = prev; 390 }else{ 391 size /= 4; 392 } 393 if( size>mem.szMaster ){ 394 mem.iMaster = i; 395 mem.szMaster = size; 396 } 397 } 398 } 399 400 /* 401 ** Return a block of memory of at least nBytes in size. 402 ** Return NULL if unable. 403 */ 404 static void *memsys3Malloc(int nByte){ 405 u32 i; 406 int nBlock; 407 int toFree; 408 409 assert( sqlite3_mutex_held(mem.mutex) ); 410 assert( sizeof(Mem3Block)==8 ); 411 if( nByte<=12 ){ 412 nBlock = 2; 413 }else{ 414 nBlock = (nByte + 11)/8; 415 } 416 assert( nBlock >= 2 ); 417 418 /* STEP 1: 419 ** Look for an entry of the correct size in either the small 420 ** chunk table or in the large chunk hash table. This is 421 ** successful most of the time (about 9 times out of 10). 422 */ 423 if( nBlock <= MX_SMALL ){ 424 i = mem.aiSmall[nBlock-2]; 425 if( i>0 ){ 426 memsys3UnlinkFromList(i, &mem.aiSmall[nBlock-2]); 427 return memsys3Checkout(i, nBlock); 428 } 429 }else{ 430 int hash = nBlock % N_HASH; 431 for(i=mem.aiHash[hash]; i>0; i=mem.aPool[i].u.list.next){ 432 if( mem.aPool[i-1].u.hdr.size4x/4==nBlock ){ 433 memsys3UnlinkFromList(i, &mem.aiHash[hash]); 434 return memsys3Checkout(i, nBlock); 435 } 436 } 437 } 438 439 /* STEP 2: 440 ** Try to satisfy the allocation by carving a piece off of the end 441 ** of the master chunk. This step usually works if step 1 fails. 442 */ 443 if( mem.szMaster>=nBlock ){ 444 return memsys3FromMaster(nBlock); 445 } 446 447 448 /* STEP 3: 449 ** Loop through the entire memory pool. Coalesce adjacent free 450 ** chunks. Recompute the master chunk as the largest free chunk. 451 ** Then try again to satisfy the allocation by carving a piece off 452 ** of the end of the master chunk. This step happens very 453 ** rarely (we hope!) 454 */ 455 for(toFree=nBlock*16; toFree<SQLITE_MEMORY_SIZE*2; toFree *= 2){ 456 memsys3OutOfMemory(toFree); 457 if( mem.iMaster ){ 458 memsys3Link(mem.iMaster); 459 mem.iMaster = 0; 460 mem.szMaster = 0; 461 } 462 for(i=0; i<N_HASH; i++){ 463 memsys3Merge(&mem.aiHash[i]); 464 } 465 for(i=0; i<MX_SMALL-1; i++){ 466 memsys3Merge(&mem.aiSmall[i]); 467 } 468 if( mem.szMaster ){ 469 memsys3Unlink(mem.iMaster); 470 if( mem.szMaster>=nBlock ){ 471 return memsys3FromMaster(nBlock); 472 } 473 } 474 } 475 476 /* If none of the above worked, then we fail. */ 477 return 0; 478 } 479 480 /* 481 ** Free an outstanding memory allocation. 482 */ 483 void memsys3Free(void *pOld){ 484 Mem3Block *p = (Mem3Block*)pOld; 485 int i; 486 u32 size, x; 487 assert( sqlite3_mutex_held(mem.mutex) ); 488 assert( p>mem.aPool && p<&mem.aPool[SQLITE_MEMORY_SIZE/8] ); 489 i = p - mem.aPool; 490 assert( (mem.aPool[i-1].u.hdr.size4x&1)==1 ); 491 size = mem.aPool[i-1].u.hdr.size4x/4; 492 assert( i+size<=SQLITE_MEMORY_SIZE/8+1 ); 493 mem.aPool[i-1].u.hdr.size4x &= ~1; 494 mem.aPool[i+size-1].u.hdr.prevSize = size; 495 mem.aPool[i+size-1].u.hdr.size4x &= ~2; 496 memsys3Link(i); 497 498 /* Try to expand the master using the newly freed chunk */ 499 if( mem.iMaster ){ 500 while( (mem.aPool[mem.iMaster-1].u.hdr.size4x&2)==0 ){ 501 size = mem.aPool[mem.iMaster-1].u.hdr.prevSize; 502 mem.iMaster -= size; 503 mem.szMaster += size; 504 memsys3Unlink(mem.iMaster); 505 x = mem.aPool[mem.iMaster-1].u.hdr.size4x & 2; 506 mem.aPool[mem.iMaster-1].u.hdr.size4x = mem.szMaster*4 | x; 507 mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster; 508 } 509 x = mem.aPool[mem.iMaster-1].u.hdr.size4x & 2; 510 while( (mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size4x&1)==0 ){ 511 memsys3Unlink(mem.iMaster+mem.szMaster); 512 mem.szMaster += mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size4x/4; 513 mem.aPool[mem.iMaster-1].u.hdr.size4x = mem.szMaster*4 | x; 514 mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster; 515 } 516 } 517 } 518 519 /* 520 ** Allocate nBytes of memory 521 */ 522 void *sqlite3_malloc(int nBytes){ 523 sqlite3_int64 *p = 0; 524 if( nBytes>0 ){ 525 memsys3Enter(); 526 p = memsys3Malloc(nBytes); 527 sqlite3_mutex_leave(mem.mutex); 528 } 529 return (void*)p; 530 } 531 532 /* 533 ** Free memory. 534 */ 535 void sqlite3_free(void *pPrior){ 536 if( pPrior==0 ){ 537 return; 538 } 539 assert( mem.mutex!=0 ); 540 sqlite3_mutex_enter(mem.mutex); 541 memsys3Free(pPrior); 542 sqlite3_mutex_leave(mem.mutex); 543 } 544 545 /* 546 ** Change the size of an existing memory allocation 547 */ 548 void *sqlite3_realloc(void *pPrior, int nBytes){ 549 int nOld; 550 void *p; 551 if( pPrior==0 ){ 552 return sqlite3_malloc(nBytes); 553 } 554 if( nBytes<=0 ){ 555 sqlite3_free(pPrior); 556 return 0; 557 } 558 assert( mem.mutex!=0 ); 559 nOld = sqlite3MallocSize(pPrior); 560 if( nBytes<=nOld && nBytes>=nOld-128 ){ 561 return pPrior; 562 } 563 sqlite3_mutex_enter(mem.mutex); 564 p = memsys3Malloc(nBytes); 565 if( p ){ 566 if( nOld<nBytes ){ 567 memcpy(p, pPrior, nOld); 568 }else{ 569 memcpy(p, pPrior, nBytes); 570 } 571 memsys3Free(pPrior); 572 } 573 sqlite3_mutex_leave(mem.mutex); 574 return p; 575 } 576 577 /* 578 ** Open the file indicated and write a log of all unfreed memory 579 ** allocations into that log. 580 */ 581 void sqlite3MemdebugDump(const char *zFilename){ 582 #ifdef SQLITE_DEBUG 583 FILE *out; 584 int i, j; 585 u32 size; 586 if( zFilename==0 || zFilename[0]==0 ){ 587 out = stdout; 588 }else{ 589 out = fopen(zFilename, "w"); 590 if( out==0 ){ 591 fprintf(stderr, "** Unable to output memory debug output log: %s **\n", 592 zFilename); 593 return; 594 } 595 } 596 memsys3Enter(); 597 fprintf(out, "CHUNKS:\n"); 598 for(i=1; i<=SQLITE_MEMORY_SIZE/8; i+=size/4){ 599 size = mem.aPool[i-1].u.hdr.size4x; 600 if( size/4<=1 ){ 601 fprintf(out, "%p size error\n", &mem.aPool[i]); 602 assert( 0 ); 603 break; 604 } 605 if( (size&1)==0 && mem.aPool[i+size/4-1].u.hdr.prevSize!=size/4 ){ 606 fprintf(out, "%p tail size does not match\n", &mem.aPool[i]); 607 assert( 0 ); 608 break; 609 } 610 if( ((mem.aPool[i+size/4-1].u.hdr.size4x&2)>>1)!=(size&1) ){ 611 fprintf(out, "%p tail checkout bit is incorrect\n", &mem.aPool[i]); 612 assert( 0 ); 613 break; 614 } 615 if( size&1 ){ 616 fprintf(out, "%p %6d bytes checked out\n", &mem.aPool[i], (size/4)*8-8); 617 }else{ 618 fprintf(out, "%p %6d bytes free%s\n", &mem.aPool[i], (size/4)*8-8, 619 i==mem.iMaster ? " **master**" : ""); 620 } 621 } 622 for(i=0; i<MX_SMALL-1; i++){ 623 if( mem.aiSmall[i]==0 ) continue; 624 fprintf(out, "small(%2d):", i); 625 for(j = mem.aiSmall[i]; j>0; j=mem.aPool[j].u.list.next){ 626 fprintf(out, " %p(%d)", &mem.aPool[j], 627 (mem.aPool[j-1].u.hdr.size4x/4)*8-8); 628 } 629 fprintf(out, "\n"); 630 } 631 for(i=0; i<N_HASH; i++){ 632 if( mem.aiHash[i]==0 ) continue; 633 fprintf(out, "hash(%2d):", i); 634 for(j = mem.aiHash[i]; j>0; j=mem.aPool[j].u.list.next){ 635 fprintf(out, " %p(%d)", &mem.aPool[j], 636 (mem.aPool[j-1].u.hdr.size4x/4)*8-8); 637 } 638 fprintf(out, "\n"); 639 } 640 fprintf(out, "master=%d\n", mem.iMaster); 641 fprintf(out, "nowUsed=%d\n", SQLITE_MEMORY_SIZE - mem.szMaster*8); 642 fprintf(out, "mxUsed=%d\n", SQLITE_MEMORY_SIZE - mem.mnMaster*8); 643 sqlite3_mutex_leave(mem.mutex); 644 if( out==stdout ){ 645 fflush(stdout); 646 }else{ 647 fclose(out); 648 } 649 #endif 650 } 651 652 653 #endif /* !SQLITE_MEMORY_SIZE */ 654