Mirko Kaffka <mirko@interface-business.de> wrote:
> We have problems with backend processes that close the channel because of
> palloc() failures. When an INSERT statement fails, the backend reports an
> error (e.g. `Cannot insert a duplicate key into a unique index') and
> allocates a few bytes more memory. The next SQL statement that fails
> causes the backend to allocate more memory again, etc. until we have no
> more virtual memory left. Is this a bug?
> We are using postgres 6.4.2 on FreeBSD 2.2.8.
I have found the primary cause of memory leakage after an error ---
basically, the backend forgets to free *any* of the temporary memory
allocated up to the point of the error :-(. If your applications tend
to provoke many SQL errors then you will see a backend process that eats
up more and more memory until it hits your local system's process size
limit, whereupon it crashes.
I have repaired this problem in the 6.5 development sources. Attached
is a patch for 6.4.2, which I suggest you apply if this sounds like a
problem you are having.
The patch does not completely eliminate memory leaks after errors, but
they seem to be reduced to the few-hundred-bytes-per-error range instead
of the kilobytes (potentially lots of kilobytes) range. I am working on
curing the problem more completely for 6.5.
regards, tom lane
*** src/backend/access/transam/xact.c.orig Thu Oct 8 14:29:15 1998
--- src/backend/access/transam/xact.c Thu May 13 18:53:05 1999
***************
*** 767,776 ****
static void
AtAbort_Memory()
{
/* ----------------
! * after doing an abort transaction, make certain the
! * system uses the top memory context rather then the
! * portal memory context (until the next transaction).
* ----------------
*/
MemoryContextSwitchTo(TopMemoryContext);
--- 767,791 ----
static void
AtAbort_Memory()
{
+ Portal portal;
+ MemoryContext portalContext;
+
/* ----------------
! * Release memory in the blank portal.
! * Since EndPortalAllocMode implicitly works on the current context,
! * first make real sure that the blank portal is the selected context.
! * (This is ESSENTIAL in case we aborted from someplace where it wasn't.)
! * ----------------
! */
! portal = GetPortalByName(NULL);
! portalContext = (MemoryContext) PortalGetHeapMemory(portal);
! MemoryContextSwitchTo(portalContext);
! EndPortalAllocMode();
!
! /* ----------------
! * Now that we're "out" of a transaction, have the
! * system allocate things in the top memory context instead
! * of the blank portal memory context.
* ----------------
*/
MemoryContextSwitchTo(TopMemoryContext);