readme
来自「postgresql8.3.4源码,开源数据库」· 代码 · 共 432 行 · 第 1/2 页
TXT
432 行
$PostgreSQL: pgsql/src/backend/utils/mmgr/README,v 1.11 2007/05/29 04:19:35 neilc Exp $Notes about memory allocation redesign--------------------------------------Up through version 7.0, Postgres had serious problems with memory leakageduring large queries that process a lot of pass-by-reference data. Therewas no provision for recycling memory until end of query. This needs to befixed, even more so with the advent of TOAST which will allow very largechunks of data to be passed around in the system. This document describesthe new memory management plan implemented in 7.1.Background----------We already do most of our memory allocation in "memory contexts", whichare usually AllocSets as implemented by backend/utils/mmgr/aset.c. Whatwe need to do is create more contexts and define proper rules about whenthey can be freed.The basic operations on a memory context are:* create a context* allocate a chunk of memory within a context (equivalent of standard C library's malloc())* delete a context (including freeing all the memory allocated therein)* reset a context (free all memory allocated in the context, but not the context object itself)Given a chunk of memory previously allocated from a context, one canfree it or reallocate it larger or smaller (corresponding to standardlibrary's free() and realloc() routines). These operations return memoryto or get more memory from the same context the chunk was originallyallocated in.At all times there is a "current" context denoted by theCurrentMemoryContext global variable. The backend macro palloc()implicitly allocates space in that context. The MemoryContextSwitchTo()operation selects a new current context (and returns the previous context,so that the caller can restore the previous context before exiting).The main advantage of memory contexts over plain use of malloc/free isthat the entire contents of a memory context can be freed easily, withouthaving to request freeing of each individual chunk within it. This isboth faster and more reliable than per-chunk bookkeeping. We already usethis fact to clean up at transaction end: by resetting all the activecontexts, we reclaim all memory. What we need are additional contextsthat can be reset or deleted at strategic times within a query, such asafter each tuple.Some notes about the palloc API versus standard C library---------------------------------------------------------The behavior of palloc and friends is similar to the standard C library'smalloc and friends, but there are some deliberate differences too. Hereare some notes to clarify the behavior.* If out of memory, palloc and repalloc exit via elog(ERROR). They neverreturn NULL, and it is not necessary or useful to test for such a result.* palloc(0) is explicitly a valid operation. It does not return a NULLpointer, but a valid chunk of which no bytes may be used. (However, thechunk might later be repalloc'd larger; it can also be pfree'd withouterror.) (Note: this behavior is new in Postgres 8.0; earlier versionsdisallowed palloc(0). It seems more consistent to allow it, however.)Similarly, repalloc allows realloc'ing to zero size.* pfree and repalloc do not accept a NULL pointer. This is intentional.pfree/repalloc no longer depend on CurrentMemoryContext-------------------------------------------------------In this proposal, pfree() and repalloc() can be applied to any chunkwhether it belongs to CurrentMemoryContext or not --- the chunk's owningcontext will be invoked to handle the operation, regardless. This is achange from the old requirement that CurrentMemoryContext must be setto the same context the memory was allocated from before one can usepfree() or repalloc(). The old coding requirement is obviously fairlyerror-prone, and will become more so the more context-switching we do;so I think it's essential to use CurrentMemoryContext only for palloc.We can avoid needing it for pfree/repalloc by putting restrictions oncontext managers as discussed below.We could even consider getting rid of CurrentMemoryContext entirely,instead requiring the target memory context for allocation to be specifiedexplicitly. But I think that would be too much notational overhead ---we'd have to pass an appropriate memory context to called routines inmany places. For example, the copyObject routines would need to be passeda context, as would function execution routines that return apass-by-reference datatype. And what of routines that temporarilyallocate space internally, but don't return it to their caller? Wecertainly don't want to clutter every call in the system with "here isa context to use for any temporary memory allocation you might want todo". So there'd still need to be a global variable specifying a suitabletemporary-allocation context. That might as well be CurrentMemoryContext.Additions to the memory-context mechanism-----------------------------------------If we are going to have more contexts, we need more mechanism for keepingtrack of them; else we risk leaking whole contexts under error conditions.We can do this by creating trees of "parent" and "child" contexts. Whencreating a memory context, the new context can be specified to be a childof some existing context. A context can have many children, but only oneparent. In this way the contexts form a forest (not necessarily a singletree, since there could be more than one top-level context).We then say that resetting or deleting any particular context resets ordeletes all its direct and indirect children as well. This feature allowsus to manage a lot of contexts without fear that some will be leaked; weonly need to keep track of one top-level context that we are going todelete at transaction end, and make sure that any shorter-lived contextswe create are descendants of that context. Since the tree can havemultiple levels, we can deal easily with nested lifetimes of storage,such as per-transaction, per-statement, per-scan, per-tuple. Storagelifetimes that only partially overlap can be handled by allocatingfrom different trees of the context forest (there are some examplesin the next section).For convenience we will also want operations like "reset/delete allchildren of a given context, but don't reset or delete that contextitself".Globally known contexts-----------------------There will be several widely-known contexts that will typically bereferenced through global variables. At any instant the system maycontain many additional contexts, but all other contexts should be director indirect children of one of these contexts to ensure they are notleaked in event of an error.TopMemoryContext --- this is the actual top level of the context tree;every other context is a direct or indirect child of this one. Allocatinghere is essentially the same as "malloc", because this context will neverbe reset or deleted. This is for stuff that should live forever, or forstuff that the controlling module will take care of deleting at theappropriate time. An example is fd.c's tables of open files, as well asthe context management nodes for memory contexts themselves. Avoidallocating stuff here unless really necessary, and especially avoidrunning with CurrentMemoryContext pointing here.PostmasterContext --- this is the postmaster's normal working context.After a backend is spawned, it can delete PostmasterContext to free itscopy of memory the postmaster was using that it doesn't need. (Anythingthat has to be passed from postmaster to backends will be passed inTopMemoryContext. The postmaster will have only TopMemoryContext,PostmasterContext, and ErrorContext --- the remaining top-level contextswill be set up in each backend during startup.)CacheMemoryContext --- permanent storage for relcache, catcache, andrelated modules. This will never be reset or deleted, either, so it'snot truly necessary to distinguish it from TopMemoryContext. But itseems worthwhile to maintain the distinction for debugging purposes.(Note: CacheMemoryContext will have child-contexts with shorter lifespans.For example, a child context is the best place to keep the subsidiarystorage associated with a relcache entry; that way we can free ruleparsetrees and so forth easily, without having to depend on constructinga reliable version of freeObject().)MessageContext --- this context holds the current command message from thefrontend, as well as any derived storage that need only live as long asthe current message (for example, in simple-Query mode the parse and plantrees can live here). This context will be reset, and any childrendeleted, at the top of each cycle of the outer loop of PostgresMain. Thisis kept separate from per-transaction and per-portal contexts because aquery string might need to live either a longer or shorter time than anysingle transaction or portal.TopTransactionContext --- this holds everything that lives until end of thetop-level transaction. This context will be reset, and all its childrendeleted, at conclusion of each top-level transaction cycle. In most casesyou don't want to allocate stuff directly here, but in CurTransactionContext;what does belong here is control information that exists explicitly to managestatus across multiple subtransactions. Note: this context is NOT clearedimmediately upon error; its contents will survive until the transaction blockis exited by COMMIT/ROLLBACK.CurTransactionContext --- this holds data that has to survive until the endof the current transaction, and in particular will be needed at top-leveltransaction commit. When we are in a top-level transaction this is the sameas TopTransactionContext, but in subtransactions it points to a child context.It is important to understand that if a subtransaction aborts, itsCurTransactionContext is thrown away after finishing the abort processing;but a committed subtransaction's CurTransactionContext is kept until top-levelcommit (unless of course one of the intermediate levels of subtransactionaborts). This ensures that we do not keep data from a failed subtransactionlonger than necessary. Because of this behavior, you must be careful to cleanup properly during subtransaction abort --- the subtransaction's state must bedelinked from any pointers or lists kept in upper transactions, or you willhave dangling pointers leading to a crash at top-level commit. An example ofdata kept here is pending NOTIFY messages, which are sent at top-level commit,but only if the generating subtransaction did not abort.PortalContext --- this is not actually a separate context, but aglobal variable pointing to the per-portal context of the currently activeexecution portal. This can be used if it's necessary to allocate storagethat will live just as long as the execution of the current portal requires.ErrorContext --- this permanent context will be switched into for errorrecovery processing, and then reset on completion of recovery. We'llarrange to have, say, 8K of memory available in it at all times. In thisway, we can ensure that some memory is available for error recovery evenif the backend has run out of memory otherwise. This allows out-of-memoryto be treated as a normal ERROR condition, not a FATAL error.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?