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