Sei sulla pagina 1di 28

Dynamic Memory Allocation

in
SQLite Core

Lookaside Page Cache Scratch


Heap Memory
Memory Memory Memory
Allocator
Allocator Allocator Allocator

failover
SQLite Core

Lookaside Page Cache Scratch


Heap Memory
Memory Memory Memory
Allocator
Allocator Allocator Allocator

failover

100 slots obtained


Wrapper around 500 slots of 128 from heap for each
bytes each, per No space allocated.
system malloc() open database file. Always fails over
connection, obtained
to heap.
from heap.
Fragmentation

Fragmentation (n): A phenomenon in which storage space is used


inefficiently, reducing storage capacity.
Internal Fragmentation
Object requests N bytes

X
Gets back N+X bytes

Internal Fragmentation is the X bytes of


unused (wasted) space.

A “clownshoe” allocation is when X is a


Heap
significant fraction of N.
External Fragmentation

N Object requests and receives


4 allocations of N bytes each

Heap
External Fragmentation

Object returns 2 of 4 allocations


to the heap

Heap
External Fragmentation

Object requests a single 2N


byte allocation.

Failed! Even though more than 2N bytes


of memory are free, there is no contiguous
block of 2N bytes free.
N

Heap
Minimum Required Heap Size
● n: max size of any memory allocation
● M: max memory outstanding
● H: heap size to avoid breakdown

H = M(1 + 0.5*log2(n)) – n + 1

J. M. Robson, Journal of the Association of Computing Machinery,


Vol 21, No. 3, July 1974, pp 491-499.
Minimum Heap Size Example 1
● Allocation sizes from 16 to 16384 bytes. n =
1024
● Max memory in use, 1 MiB. M = 65536
● H = 393207 or about 6.3 MB.
● Never use more than about 16.5% of memory
Maximum Heap Size Example 2
● All allocations are exactly 4200 bytes. n = 1
● Maximum memory used is 1 MB. M = 238.
● H = 238 or 1 MB.
● 100% memory utilization

● To maximize memory utilization, keep n small


Efforts to keep n small
● Three memory pools with n=1
– Page cache
– Scratch memory
– Lookaside memory
● No large objects: n can be as small as 4 or 8 in
the general-purpose allocator
● Automatic fail-over from the n=1 pools to the
general-purpose allocator
Preventing Fragmentation
● Use sqlite3_config() to supply buffers for n=1
memory pools
● Use SQLITE_ENABLE_MEMSYS5 to enable a
Robson-compliant allocator
● Use sqlite3_status() to track n and M and avoid
going over limits.
● Choose a large minimum allocation size (using
sqlite3_config) to help limit the size of n
● Avoid large table rows
Lookaside Memory Allocator
● One per database connection
● Fixed allocation size: Approx 100 to 200 bytes
– n=1
● A few hundred to a few thousand slots
● Faster than the general-purpose allocator
– No mutexes
– Simpler algorithm
● Automatic failover to general-purpose allocator
Lookaside Configuration
● Default:
– 500 slots of 128 bytes each
– Pool space obtained from heap memory allocator
● Use sqlite3_config() to set default sizes
● Use sqlite3_db_config() to set custom sizes or
assign static pool memory
● Use sqlite3_db_status() to see current usage
and highwater mark
Page Cache
● One per process OR one per database file
● Fixed allocation size
– Needs to be ~300 bytes larger than page size
– Use SQLITE_CONFIG_PCACHE_HDRSZ to find
exact amount
– n=1
● Default size: 100 slots
● Automatic failover to general-purpose allocator
● Largest users of memory in most systems
Separate vs. Single Page Cache
● Default ● MEMORY_MANAGE
● Faster MENT
● No sharing - uses
● Single-threaded &
more memory static PCACHE
allocation
● Requires a mutex
● Shares memory
between connections
Page Cache Bulk Memory Allocation
sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0);

Each page stored in memory


Each page stored in memory
obtained from malloc(). Separate
obtained from sqlite3_malloc().
malloc() or each page.

sqlite3_config(SQLITE_CONFIG_PAGECACHE, pMem, sz, N);

Use pMem to store pages.


Failover to malloc() when pMem
is used up.
Page Cache Bulk Memory Allocation
Must be NULL/zero.

sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, N);

Single malloc() sufficient to store N


pages. Individual malloc() calls for
more.

sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, -N);

Single malloc() for N*1024 bytes.


Individual malloc() calls beyond that.
Scratch Memory
● Two allocations per thread, max
● Allocation size approx 6x page size
● Default size: 0 slots
● Automatic fail-over to general purpose allocator
● Used to avoid a large general-purpose
allocation in the b-tree balancer and hence
keep n small
General Purpose Memory Allocator
● Uses system malloc() by default
● MEMSYS5 or others available as options
● Replaceable at start-time
– Custom allocator simulates OOM errors for testing
sqlite3_msize()
● On unix you want: HAVE_MALLOC_H and
HAVE_MALLOC_USABLE_SIZE so that
malloc_usable_size() will be used
● Windows uses _msize()
● Mac uses malloc_zone_t->size()

Without these, SQLite allocates 8 extra bytes


and stores the allocation size in those 8 bytes.
sqlite3_msize()

size_t N = 1000 /* Size of hash­tab/buffer/cache */;
void *p = sqlite3_malloc64(N);
N = sqlite3_msize(p);

/* Use all N bytes of p ... */
sqlite3_status64()
● General purpose memory used
● Largest GP allocation size
● Page cache slots used
● Page cache overflows to GP allocator
● Largest page cache allocation size
● Scratch memory used
● Scratch memory overflows to GP allocator
● Largest scratch memory allocation size
.stats on
Memory Used: 189184 (max 192512) bytes
Number of Outstanding Allocations: 1070 (max 1128)
Number of Pcache Overflow Bytes: 46824 (max 46824) bytes
Number of Scratch Overflow Bytes: 0 (max 0) bytes
Largest Allocation: 64000 bytes
Largest Pcache Allocation: 1272 bytes
Largest Scratch Allocation: 0 bytes
Lookaside Slots Used: 3 (max 81)
Successful lookaside attempts: 399
Lookaside failures due to size: 157
Lookaside failures due to OOM: 0
Pager Heap Usage: 47192 bytes
Page cache hits: 30
Page cache misses: 36
Page cache writes: 0
Schema Heap Usage: 69592 bytes
Statement Heap/Lookaside Usage: 1808 bytes
Fullscan Steps: 0
Sort Operations: 0
Autoindex Inserts: 0
Virtual Machine Steps: 10
Memory Sizing
● Rule of thumb: more memory = faster
● 50 to 100 cache pages per database
connection
● 2 to 50 kB per prepared statement
● Schema parse is held in memory – avoid overly
complex schemas
Custom Page Cache
● Dynamically sized according to system load?
● Discard pages when under memory pressure?
● Setup using sqlite3_config()
struct sqlite3_pcache_methods2 {
int iVersion;
void *pArg;
int (*xInit)(void*);
void (*xShutdown)(void*);
sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable);
void (*xCachesize)(sqlite3_pcache*, int nCachesize);
int (*xPagecount)(sqlite3_pcache*);
sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
unsigned oldKey, unsigned newKey);
void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
void (*xDestroy)(sqlite3_pcache*);
void (*xShrink)(sqlite3_pcache*);
};
PRAGMA temp_store
● PRAGMA temp_store=FILE;
– Temporary data stored on disk
– Less memory used, but slower
● PRAGMA temp_store=MEMORY;
– Temporary data stored in RAM
– Faster, but uses more memory
● Default behavior determined by
SQLITE_TEMP_STORE compile-time option

Potrebbero piacerti anche