1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "AutoSQLiteLifetime.h"
11 # include "mozmemory.h"
13 # include "nsIMemoryReporter.h"
18 extern mozilla::Atomic
<size_t> gSqliteMemoryUsed
;
20 } // namespace mozilla
22 using mozilla::storage::gSqliteMemoryUsed
;
28 // By default, SQLite tracks the size of all its heap blocks by adding an extra
29 // 8 bytes at the start of the block to hold the size. Unfortunately, this
30 // causes a lot of 2^N-sized allocations to be rounded up by jemalloc
31 // allocator, wasting memory. For example, a request for 1024 bytes has 8
32 // bytes added, becoming a request for 1032 bytes, and jemalloc rounds this up
33 // to 2048 bytes, wasting 1012 bytes. (See bug 676189 for more details.)
35 // So we register jemalloc as the malloc implementation, which avoids this
36 // 8-byte overhead, and thus a lot of waste. This requires us to provide a
37 // function, sqliteMemRoundup(), which computes the actual size that will be
38 // allocated for a given request. SQLite uses this function before all
39 // allocations, and may be able to use any excess bytes caused by the rounding.
41 // Note: the wrappers for malloc, realloc and moz_malloc_usable_size are
42 // necessary because the sqlite_mem_methods type signatures differ slightly
43 // from the standard ones -- they use int instead of size_t. But we don't need
44 // a wrapper for free.
48 // sqlite does its own memory accounting, and we use its numbers in our memory
49 // reporters. But we don't want sqlite's heap blocks to show up in DMD's
50 // output as unreported, so we mark them as reported when they're allocated and
51 // mark them as unreported when they are freed.
53 // In other words, we are marking all sqlite heap blocks as reported even
54 // though we're not reporting them ourselves. Instead we're trusting that
55 // sqlite is fully and correctly accounting for all of its heap blocks via its
56 // own memory accounting. Well, we don't have to trust it entirely, because
57 // it's easy to keep track (while doing this DMD-specific marking) of exactly
58 // how much memory SQLite is using. And we can compare that against what
59 // SQLite reports it is using.
61 MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(SqliteMallocSizeOfOnAlloc
)
62 MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(SqliteMallocSizeOfOnFree
)
66 static void* sqliteMemMalloc(int n
) {
67 void* p
= ::malloc(n
);
69 gSqliteMemoryUsed
+= SqliteMallocSizeOfOnAlloc(p
);
74 static void sqliteMemFree(void* p
) {
76 gSqliteMemoryUsed
-= SqliteMallocSizeOfOnFree(p
);
81 static void* sqliteMemRealloc(void* p
, int n
) {
83 gSqliteMemoryUsed
-= SqliteMallocSizeOfOnFree(p
);
84 void* pnew
= ::realloc(p
, n
);
86 gSqliteMemoryUsed
+= SqliteMallocSizeOfOnAlloc(pnew
);
88 // realloc failed; undo the SqliteMallocSizeOfOnFree from above
89 gSqliteMemoryUsed
+= SqliteMallocSizeOfOnAlloc(p
);
93 return ::realloc(p
, n
);
97 static int sqliteMemSize(void* p
) { return ::moz_malloc_usable_size(p
); }
99 static int sqliteMemRoundup(int n
) {
100 n
= malloc_good_size(n
);
102 // jemalloc can return blocks of size 2 and 4, but SQLite requires that all
103 // allocations be 8-aligned. So we round up sub-8 requests to 8. This
104 // wastes a small amount of memory but is obviously safe.
105 return n
<= 8 ? 8 : n
;
108 static int sqliteMemInit(void* p
) { return 0; }
110 static void sqliteMemShutdown(void* p
) {}
112 const sqlite3_mem_methods memMethods
= {
113 &sqliteMemMalloc
, &sqliteMemFree
, &sqliteMemRealloc
, &sqliteMemSize
,
114 &sqliteMemRoundup
, &sqliteMemInit
, &sqliteMemShutdown
, nullptr};
122 AutoSQLiteLifetime::AutoSQLiteLifetime() {
123 if (++AutoSQLiteLifetime::sSingletonEnforcer
!= 1) {
124 MOZ_CRASH("multiple instances of AutoSQLiteLifetime constructed!");
128 sResult
= ::sqlite3_config(SQLITE_CONFIG_MALLOC
, &memMethods
);
133 if (sResult
== SQLITE_OK
) {
134 // TODO (bug 1191405): do not preallocate the connections caches until we
135 // have figured the impact on our consumers and memory.
136 sqlite3_config(SQLITE_CONFIG_PAGECACHE
, NULL
, 0, 0);
138 // Explicitly initialize sqlite3. Although this is implicitly called by
139 // various sqlite3 functions (and the sqlite3_open calls in our case),
140 // the documentation suggests calling this directly. So we do.
141 sResult
= ::sqlite3_initialize();
145 AutoSQLiteLifetime::~AutoSQLiteLifetime() {
146 // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but
147 // there is nothing actionable we can do in that case.
148 sResult
= ::sqlite3_shutdown();
149 NS_WARNING_ASSERTION(sResult
== SQLITE_OK
,
150 "sqlite3 did not shutdown cleanly.");
153 int AutoSQLiteLifetime::sSingletonEnforcer
= 0;
154 int AutoSQLiteLifetime::sResult
= SQLITE_MISUSE
;
156 } // namespace mozilla