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.8 2007/12/29 13:18:22 drh Exp $ 24 */ 25 26 /* 27 ** This version of the memory allocator is used only when 28 ** SQLITE_MEMORY_SIZE is defined. 29 */ 30 #if defined(SQLITE_MEMORY_SIZE) 31 #include "sqliteInt.h" 32 33 #ifdef SQLITE_MEMDEBUG 34 # error cannot define both SQLITE_MEMDEBUG and SQLITE_MEMORY_SIZE 35 #endif 36 37 /* 38 ** Maximum size (in Mem3Blocks) of a "small" chunk. 39 */ 40 #define MX_SMALL 10 41 42 43 /* 44 ** Number of freelist hash slots 45 */ 46 #define N_HASH 61 47 48 /* 49 ** A memory allocation (also called a "chunk") consists of two or 50 ** more blocks where each block is 8 bytes. The first 8 bytes are 51 ** a header that is not returned to the user. 52 ** 53 ** A chunk is two or more blocks that is either checked out or 54 ** free. The first block has format u.hdr. u.hdr.size4x is 4 times the 55 ** size of the allocation in blocks if the allocation is free. 56 ** The u.hdr.size4x&1 bit is true if the chunk is checked out and 57 ** false if the chunk is on the freelist. The u.hdr.size4x&2 bit 58 ** is true if the previous chunk is checked out and false if the 59 ** previous chunk is free. The u.hdr.prevSize field is the size of 60 ** the previous chunk in blocks if the previous chunk is on the 61 ** freelist. If the previous chunk is checked out, then 62 ** u.hdr.prevSize can be part of the data for that chunk and should 63 ** not be read or written. 64 ** 65 ** We often identify a chunk by its index in mem.aPool[]. When 66 ** this is done, the chunk index refers to the second block of 67 ** the chunk. In this way, the first chunk has an index of 1. 68 ** A chunk index of 0 means "no such chunk" and is the equivalent 69 ** of a NULL pointer. 70 ** 71 ** The second block of free chunks is of the form u.list. The 72 ** two fields form a double-linked list of chunks of related sizes. 73 ** Pointers to the head of the list are stored in mem.aiSmall[] 74 ** for smaller chunks and mem.aiHash[] for larger chunks. 75 ** 76 ** The second block of a chunk is user data if the chunk is checked 77 ** out. If a chunk is checked out, the user data may extend into 78 ** the u.hdr.prevSize value of the following chunk. 79 */ 80 typedef struct Mem3Block Mem3Block; 81 struct Mem3Block { 82 union { 83 struct { 84 u32 prevSize; /* Size of previous chunk in Mem3Block elements */ 85 u32 size4x; /* 4x the size of current chunk in Mem3Block elements */ 86 } hdr; 87 struct { 88 u32 next; /* Index in mem.aPool[] of next free chunk */ 89 u32 prev; /* Index in mem.aPool[] of previous free chunk */ 90 } list; 91 } u; 92 }; 93 94 /* 95 ** All of the static variables used by this module are collected 96 ** into a single structure named "mem". This is to keep the 97 ** static variables organized and to reduce namespace pollution 98 ** when this module is combined with other in the amalgamation. 99 */ 100 static struct { 101 /* 102 ** True if we are evaluating an out-of-memory callback. 103 */ 104 int alarmBusy; 105 106 /* 107 ** Mutex to control access to the memory allocation subsystem. 108 */ 109 sqlite3_mutex *mutex; 110 111 /* 112 ** The minimum amount of free space that we have seen. 113 */ 114 u32 mnMaster; 115 116 /* 117 ** iMaster is the index of the master chunk. Most new allocations 118 ** occur off of this chunk. szMaster is the size (in Mem3Blocks) 119 ** of the current master. iMaster is 0 if there is not master chunk. 120 ** The master chunk is not in either the aiHash[] or aiSmall[]. 121 */ 122 u32 iMaster; 123 u32 szMaster; 124 125 /* 126 ** Array of lists of free blocks according to the block size 127 ** for smaller chunks, or a hash on the block size for larger 128 ** chunks. 129 */ 130 u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */ 131 u32 aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */ 132 133 /* 134 ** Memory available for allocation 135 */ 136 Mem3Block aPool[SQLITE_MEMORY_SIZE/sizeof(Mem3Block)+2]; 137 } mem; 138 139 /* 140 ** Unlink the chunk at mem.aPool[i] from list it is currently 141 ** on. *pRoot is the list that i is a member of. 142 */ 143 static void memsys3UnlinkFromList(u32 i, u32 *pRoot){ 144 u32 next = mem.aPool[i].u.list.next; 145 u32 prev = mem.aPool[i].u.list.prev; 146 assert( sqlite3_mutex_held(mem.mutex) ); 147 if( prev==0 ){ 148 *pRoot = next; 149 }else{ 150 mem.aPool[prev].u.list.next = next; 151 } 152 if( next ){ 153 mem.aPool[next].u.list.prev = prev; 154 } 155 mem.aPool[i].u.list.next = 0; 156 mem.aPool[i].u.list.prev = 0; 157 } 158 159 /* 160 ** Unlink the chunk at index i from 161 ** whatever list is currently a member of. 162 */ 163 static void memsys3Unlink(u32 i){ 164 u32 size, hash; 165 assert( sqlite3_mutex_held(mem.mutex) ); 166 assert( (mem.aPool[i-1].u.hdr.size4x & 1)==0 ); 167 assert( i>=1 ); 168 size = mem.aPool[i-1].u.hdr.size4x/4; 169 assert( size==mem.aPool[i+size-1].u.hdr.prevSize ); 170 assert( size>=2 ); 171 if( size <= MX_SMALL ){ 172 memsys3UnlinkFromList(i, &mem.aiSmall[size-2]); 173 }else{ 174 hash = size % N_HASH; 175 memsys3UnlinkFromList(i, &mem.aiHash[hash]); 176 } 177 } 178 179 /* 180 ** Link the chunk at mem.aPool[i] so that is on the list rooted 181 ** at *pRoot. 182 */ 183 static void memsys3LinkIntoList(u32 i, u32 *pRoot){ 184 assert( sqlite3_mutex_held(mem.mutex) ); 185 mem.aPool[i].u.list.next = *pRoot; 186 mem.aPool[i].u.list.prev = 0; 187 if( *pRoot ){ 188 mem.aPool[*pRoot].u.list.prev = i; 189 } 190 *pRoot = i; 191 } 192 193 /* 194 ** Link the chunk at index i into either the appropriate 195 ** small chunk list, or into the large chunk hash table. 196 */ 197 static void memsys3Link(u32 i){ 198 u32 size, hash; 199 assert( sqlite3_mutex_held(mem.mutex) ); 200 assert( i>=1 ); 201 assert( (mem.aPool[i-1].u.hdr.size4x & 1)==0 ); 202 size = mem.aPool[i-1].u.hdr.size4x/4; 203 assert( size==mem.aPool[i+size-1].u.hdr.prevSize ); 204 assert( size>=2 ); 205 if( size <= MX_SMALL ){ 206 memsys3LinkIntoList(i, &mem.aiSmall[size-2]); 207 }else{ 208 hash = size % N_HASH; 209 memsys3LinkIntoList(i, &mem.aiHash[hash]); 210 } 211 } 212 213 /* 214 ** Enter the mutex mem.mutex. Allocate it if it is not already allocated. 215 ** 216 ** Also: Initialize the memory allocation subsystem the first time 217 ** this routine is called. 218 */ 219 static void memsys3Enter(void){ 220 if( mem.mutex==0 ){ 221 mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); 222 mem.aPool[0].u.hdr.size4x = SQLITE_MEMORY_SIZE/2 + 2; 223 mem.aPool[SQLITE_MEMORY_SIZE/8].u.hdr.prevSize = SQLITE_MEMORY_SIZE/8; 224 mem.aPool[SQLITE_MEMORY_SIZE/8].u.hdr.size4x = 1; 225 mem.iMaster = 1; 226 mem.szMaster = SQLITE_MEMORY_SIZE/8; 227 mem.mnMaster = mem.szMaster; 228 } 229 sqlite3_mutex_enter(mem.mutex); 230 } 231 232 /* 233 ** Return the amount of memory currently checked out. 234 */ 235 sqlite3_int64 sqlite3_memory_used(void){ 236 sqlite3_int64 n; 237 memsys3Enter(); 238 n = SQLITE_MEMORY_SIZE - mem.szMaster*8; 239 sqlite3_mutex_leave(mem.mutex); 240 return n; 241 } 242 243 /* 244 ** Return the maximum amount of memory that has ever been 245 ** checked out since either the beginning of this process 246 ** or since the most recent reset. 247 */ 248 sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ 249 sqlite3_int64 n; 250 memsys3Enter(); 251 n = SQLITE_MEMORY_SIZE - mem.mnMaster*8; 252 if( resetFlag ){ 253 mem.mnMaster = mem.szMaster; 254 } 255 sqlite3_mutex_leave(mem.mutex); 256 return n; 257 } 258 259 /* 260 ** Change the alarm callback. 261 ** 262 ** This is a no-op for the static memory allocator. The purpose 263 ** of the memory alarm is to support sqlite3_soft_heap_limit(). 264 ** But with this memory allocator, the soft_heap_limit is really 265 ** a hard limit that is fixed at SQLITE_MEMORY_SIZE. 266 */ 267 int sqlite3_memory_alarm( 268 void(*xCallback)(void *pArg, sqlite3_int64 used,int N), 269 void *pArg, 270 sqlite3_int64 iThreshold 271 ){ 272 return SQLITE_OK; 273 } 274 275 /* 276 ** Called when we are unable to satisfy an allocation of nBytes. 277 */ 278 static void memsys3OutOfMemory(int nByte){ 279 if( !mem.alarmBusy ){ 280 mem.alarmBusy = 1; 281 assert( sqlite3_mutex_held(mem.mutex) ); 282 sqlite3_mutex_leave(mem.mutex); 283 sqlite3_release_memory(nByte); 284 sqlite3_mutex_enter(mem.mutex); 285 mem.alarmBusy = 0; 286 } 287 } 288 289 /* 290 ** Return the size of an outstanding allocation, in bytes. The 291 ** size returned omits the 8-byte header overhead. This only 292 ** works for chunks that are currently checked out. 293 */ 294 static int memsys3Size(void *p){ 295 Mem3Block *pBlock = (Mem3Block*)p; 296 assert( (pBlock[-1].u.hdr.size4x&1)!=0 ); 297 return (pBlock[-1].u.hdr.size4x&~3)*2 - 4; 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 = memsys3Size(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 sqlite3_memdebug_dump(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