lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

On Sun, Jan 18, 2015 at 02:17:02AM +0700, David Favro wrote:
> On 01/17/2015 04:15 AM, Sean Conner wrote:
> >It was thus said that the Great Andrew Starks once stated:
> >>If you always error, you can
> >>pretend that errors never happen, until you can't. In a garbage
> >>collected language, the places where you need to clean the state up
> >>are pretty limited, so this may be more true of Lua than of C, or
> >>whathaveyou.
> >   But you can still leak resources if you don't clear your references.  I
> >just found such a bug at work at one place, and now I'm afraid of all the
> >paths I neglected to clean up references leading up to that point.
> Indeed, I recently ran into a bug in which a database transaction was 
> 'leaked', i.e. a transaction was started, an error raised in the code 
> between the start and commit, and it was pcall-caught higher up the call 
> stack, without rolling back the transaction.  The higher-level code then 
> continued using the database connection with the pending partial 
> transaction (and subsequent updates to the DB) never getting committed 
> until the process terminated and the subsequent updates were rolled back.
> In C++ this kind of thing often can be conveniently avoided by using the 
> Resource Acquisition Is Initialization paradigm, or if not, less 
> conveniently with try-catch blocks.  In Lua, I find it a bit of a PITA 
> to try to release resources using xpcall.  But frankly I prefer it to 
> "return nil,msg".

Maybe you already do this, but in Lua 5.2 and 5.3 you can catch the leak by
using the object to index a weak table, where you store a table with a __gc
metamethod hook to trigger your cleanup logic. (In Lua 5.1 you can use the
undocumented newproxy in lieu of table __gc metamethods.)

I use this as a fail-safe in several of my applications. It's basically
operates as a destructor that you can attach to objects without having to
hack their implementation (e.g. attach a __gc handler to the object itself).

Because you never know when the GC will run, I usually have a task with runs
every N seconds to step through the GC. That way leaked object recyling will
happen within bounded wallclock time, rather than based on memory pressure.
This helps to reduce GC jitter, anyhow.