readme

来自「PostgreSQL7.4.6 for Linux」· 代码 · 共 408 行 · 第 1/2 页

TXT
408
字号
$Header: /cvsroot/pgsql/src/backend/utils/mmgr/README,v 1.4 2003/04/30 19:04:12 tgl 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.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 apppropriate 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 oftransaction (longer than one statement within a transaction!).  An exampleof what has to be here is the list of pending NOTIFY messages to be sentat xact commit.  This context will be reset, and all its children deleted,at conclusion of each transaction cycle.  Note: this context is NOTcleared immediately upon error; its contents will survive until thetransaction block is exited by COMMIT/ROLLBACK.(If we ever implement nested transactions, TopTransactionContext may needto be split into a true "top" pointer and a "current transaction" pointer.)QueryContext --- this is not actually a separate context, but a globalvariable pointing to the context that holds the current command's parseand plan trees.  (In simple-Query mode this points to MessageContext;when executing a prepared statement it will point at the preparedstatement's private context.)  Generally it is not appropriate for anycode to use QueryContext as an allocation target --- from the point ofview of any code that would be referencing the QueryContext variable,it's a read-only context.PortalContext --- this is not actually a separate context either, 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.Contexts for prepared statements and portals--------------------------------------------A prepared-statement object has an associated private context, in whichthe parse and plan trees for its query are stored.  Because these treesare read-only to the executor, the prepared statement can be re-used manytimes without further copying of these trees.  QueryContext points at thisprivate context while executing any portal built from the preparedstatement.An execution-portal object has a private context that is referenced byPortalContext when the portal is active.  In the case of a portal createdby DECLARE CURSOR, this private context contains the query parse and plantrees (there being no other object that can hold them).  Portals created

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?