Обсуждение: Should I free this memory?

Поиск
Список
Период
Сортировка

Should I free this memory?

От
Jorge Arévalo
Дата:
Hello,

My C function:

PG_FUNCTION_INFO_V1(my_function);
Datum my_function(PG_FUNCTION_ARGS)
{
MemoryContext old_context;
int * p = NULL;
float f = 0.0;

old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
p = palloc(100);
MemoryContextSwitchTo(old_context);

// do some other stuff

PG_RETURN_FLOAT8(f); // I didn't call pfree(p)
}

Should I free the memory allocated for p? I'm getting memory leaks
when I don't free the memory, and they disappear when I call pfree(p);

I think the response is "yes", I should free the memory (looking at
the results), but I'm not sure why. So, maybe my real doubt is: which
memory context are fcinfo->flinfo->fn_mcxt and old_context? In which
context should I work and why?

Many thanks in advance, and best regards

--
Jorge Arévalo
Internet & Mobilty Division, DEIMOS
jorge.arevalo@deimos-space.com
http://es.linkedin.com/in/jorgearevalo80
http://mobility.grupodeimos.com/
http://gis4free.wordpress.com
http://geohash.org/ezjqgrgzz0g

Re: Should I free this memory?

От
Tom Lane
Дата:
=?ISO-8859-1?Q?Jorge_Ar=E9valo?= <jorge.arevalo@deimos-space.com> writes:
> old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
> p = palloc(100);
> MemoryContextSwitchTo(old_context);

Why are you doing that?

> Should I free the memory allocated for p? I'm getting memory leaks
> when I don't free the memory, and they disappear when I call pfree(p);

If you allocate that space again on every call, yes you'll get leaks.
The fn_mcxt context typically has query lifespan, and could be even
longer lived than that.

While you could fix it with a pfree at the end of the function, you'll
still have a leak if you lose control partway through due to some
function throwing an elog(ERROR).  By and large, if you intend to
allocate the space again on every call anyway, you should just palloc it
in your calling memory context, which has got tuple-cycle lifespan and
so doesn't pose much risk of bloat.  The only reason to allocate
something in fn_mcxt is if you're trying to cache data across successive
function calls.

            regards, tom lane

Re: Should I free this memory?

От
Jorge Arévalo
Дата:
On Sat, Apr 23, 2011 at 5:11 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> =?ISO-8859-1?Q?Jorge_Ar=E9valo?= <jorge.arevalo@deimos-space.com> writes:
>> old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
>> p = palloc(100);
>> MemoryContextSwitchTo(old_context);
>
> Why are you doing that?
>

It's a simplified example. The point is some memory is allocated in
that context and is not free'd. I'm trying to understand it. Not my
code.


>> Should I free the memory allocated for p? I'm getting memory leaks
>> when I don't free the memory, and they disappear when I call pfree(p);
>
> If you allocate that space again on every call, yes you'll get leaks.
> The fn_mcxt context typically has query lifespan, and could be even
> longer lived than that.
>
> While you could fix it with a pfree at the end of the function, you'll
> still have a leak if you lose control partway through due to some
> function throwing an elog(ERROR).  By and large, if you intend to
> allocate the space again on every call anyway, you should just palloc it
> in your calling memory context, which has got tuple-cycle lifespan and
> so doesn't pose much risk of bloat.  The only reason to allocate
> something in fn_mcxt is if you're trying to cache data across successive
> function calls.
>

Interesting. I've read the README document at src/backend/utils/mmgr,
and I have some unclear points yet:

I've understood several well-known memory contexts exist
(TopMemoryContext, CacheMemoryContext, MessageContext,
CurTransactionContext...), but I don't know what memory context are
more important for the creator of a new SQL function. It's really
important for me, because I'm extending my PostgreSQL server (version
8.4.7) with my own functions.

For example, I know every time a SQL function is called, a new memory
context is created (son of MessageMemoryContex, PortalContext,
CurTransactionContext?). Every chunk of memory allocated here by
palloc/repalloc is automatically free'd at the end of the function.
Apart from this "normal" memory context, I've identified two more
contexts:

- The one pointed by fcinfo->flinfo->fn_mcxt. It has query-cycle
persistence, you said.
- The one pointed by funcctx->multi_call_memory_ctx, in SRF. With
query-cycle persistence too, I suppose.

What's the difference between both? Reading the definition of FmgrInfo
struct at http://doxygen.postgresql.org/fmgr_8h-source.html#l00044, I
understand fn_mcxt is the memory context where the data pointed my
fn_extra is stored, it has query-cycle lifespan and must be managed by
the user (I should free'd everything). And multi_call_memory_ctx "is
the most appropriate memory context for any memory that is to be
reused across multiple calls of the SRF". But I don't know when and
where I should use them.

And another question: what's the difference between tuple-cycle and
query-cycle lifespan? In case of functions returning several rows
(SRF), I see it clear. But in case of functions returning single
values, or single rows, I can't see it.


>                        regards, tom lane
>

Many thanks for your response, and sorry for bothering you with so
many questions.

Best regards,

--
Jorge Arévalo
Internet & Mobilty Division, DEIMOS
jorge.arevalo@deimos-space.com
http://es.linkedin.com/in/jorgearevalo80
http://mobility.grupodeimos.com/
http://gis4free.wordpress.com
http://geohash.org/ezjqgrgzz0g

Re: Should I free this memory?

От
Tom Lane
Дата:
=?ISO-8859-1?Q?Jorge_Ar=E9valo?= <jorge.arevalo@deimos-space.com> writes:
> Interesting. I've read the README document at src/backend/utils/mmgr,
> and I have some unclear points yet:

> I've understood several well-known memory contexts exist
> (TopMemoryContext, CacheMemoryContext, MessageContext,
> CurTransactionContext...), but I don't know what memory context are
> more important for the creator of a new SQL function.

99% of functions never touch any of those top-level contexts.  Usually
you use the call-time CurrentMemoryContext for anything that only needs
to live as long as the function runs, and for anything you intend to
return as the function result.  If you want to cache something across
calls within a query, you store it in fn_mcxt or multi_call_memory_ctx.
There's seldom a good reason to do anything else.

> - The one pointed by fcinfo->flinfo->fn_mcxt. It has query-cycle
> persistence, you said.
> - The one pointed by funcctx->multi_call_memory_ctx, in SRF. With
> query-cycle persistence too, I suppose.

> What's the difference between both?

Not much --- in fact, I'd bet they're usually the same context.
It's a matter of which API you're using.  If you're using
flinfo->fn_extra to hold a pointer to some cached data, you should put
that cached data in fn_mcxt.  If you're relying on the funcapi.h SRF
support macros, it's better to reference multi_call_memory_ctx; touching
fn_mcxt directly would be a violation of the SRF abstraction layer.

> And another question: what's the difference between tuple-cycle and
> query-cycle lifespan? In case of functions returning several rows
> (SRF), I see it clear. But in case of functions returning single
> values, or single rows, I can't see it.

If you have say

    select concat(txt1, txt2) from table ...

the result of the concat needs to be delivered in a tuple-cycle memory
context, else you'll have a leak across the rows of the table.  But if
the function wanted to stash some information to avoid looking it up
again during each call, it'd need to put that in a query-lifespan memory
context.

There actually isn't any such thing as a context that's automatically
reset at the end of each individual function call (although some
particularly memory-hungry functions choose to implement one for
themselves).  The reason is that for example in

    select concat(txt1, txt2), concat(txt3, txt4) from table ...

both function results have to stick around until we form the result
tuple at the end of evaluating the SELECT list.  So we only reset the
context at the end of the tuple cycle, not after each function.  This
means that any internal allocations that a function neglects to pfree
are "leaked" till the end of the tuple cycle, but that's almost never
worth worrying about.

            regards, tom lane