memory leak in trigger handling (since PG12)
От | Tomas Vondra |
---|---|
Тема | memory leak in trigger handling (since PG12) |
Дата | |
Msg-id | 222a3442-7f7d-246c-ed9b-a76209d19239@enterprisedb.com обсуждение исходный текст |
Ответы |
Re: memory leak in trigger handling (since PG12)
Re: memory leak in trigger handling (since PG12) Re: memory leak in trigger handling (since PG12) Re: memory leak in trigger handling (since PG12) |
Список | pgsql-hackers |
Hi, it seems there's a fairly annoying memory leak in trigger code, introduced by commit fc22b6623b6b3bab3cb057ccd282c2bfad1a0b30 Author: Peter Eisentraut <peter@eisentraut.org> Date: Sat Mar 30 08:13:09 2019 +0100 Generated columns ... which added GetAllUpdatedColumns() and uses it many places instead of the original GetUpdatedColumns(): #define GetUpdatedColumns(relinfo, estate) \ (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols) #define GetAllUpdatedColumns(relinfo, estate) \ (bms_union(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols, \ exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols)) Notice this creates a new bitmap on every calls. That's a bit of a problem, because we call this from: - ExecASUpdateTriggers - ExecARUpdateTriggers - ExecBSUpdateTriggers - ExecBRUpdateTriggers - ExecUpdateLockMode This means that for an UPDATE with triggers, we may end up calling this for each row, possibly multiple bitmaps. And those bitmaps are allocated in ExecutorState, so won't be freed until the end of the query :-( The bitmaps are typically fairly small (a couple bytes), but for wider tables it can be a couple dozen bytes. But it's primarily driven by number of updated rows. It's easy to leak gigabytes when updating ~10M rows. I've seen cases with a couple tens of GBs leaked, though, but in that case it seems to be caused by UPDATE ... FROM missing a join condition (so in fact the memory leak is proportional to number of rows in the join result, not the number we end up updating). Attached is a patch, restoring the pre-12 behavior for me. While looking for other places allocating stuff in ExecutorState (for the UPDATE case) and leaving it there, I found two more cases: 1) copy_plpgsql_datums 2) make_expanded_record_from_tupdesc make_expanded_record_from_exprecord All of this is calls from plpgsql_exec_trigger. Fixing the copy_plpgsql_datums case seems fairly simple, the space allocated for local copies can be freed during the cleanup. That's what 0002 does. I'm not sure what to do about the expanded records. My understanding of the expanded record lifecycle is fairly limited, so my (rather naive) attempt to free the memory failed ... I wonder how much we should care about these cases. On the one hand we often leave the cleanup up to the memory context, but the assumption is the context is not unnecessarily long-lived. And ExecutorState is not that. And leaking memory per-row does not seem great either. regards -- Tomas Vondra EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company
Вложения
В списке pgsql-hackers по дате отправления: