Garbage Collector on Constrained System

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Garbage Collector on Constrained System

Ralph Hempel
I've got a bit of a problem that I hope some gurus can
help me out with.

I'm running 5.1.1 on a very memory constrained system. It's
the LEGO NXT and I have about 52K of RAM allocated to
the heap, which is controlled by malloc()

Once I've loaded the API for the NXT peripherals (C binding to Lua)
the gcinfo() tells me I have about 16K left - which I find hard
to believe. There are about 40 calls to C functions.

What can I tune in the source to force the gc to be more
aggressive, and can it work if I give it a fixed block of
memory that can never be expanded?

Also, can I force the gc to run during script evaluation?

Sometimes if a script is large or complex, the malloc()
I have simply bails and dies saying it can't allocate
any more memory.

Cheers, Ralph

Reply | Threaded
Open this post in threaded view
|

Re: Garbage Collector on Constrained System

Glenn edgar
I have the same problem.  I have to be agressive about forcing the garbage collector during loops.  When newbe's run lua for the first time on embedded systems, they have the same problem, even on heaps in the mega bytes.  ( They run over night tests.)  Lua gets a black eye because they think is memory leaks inside the engine, and I have to do a song and dance to smooth out the situation.

I thought about changing it, but in my line of work it is important not to touch the baseline and only extend and embedded.

Glenn Edgar

On 3/22/07, Ralph Hempel <[hidden email]> wrote:
I've got a bit of a problem that I hope some gurus can
help me out with.

I'm running 5.1.1 on a very memory constrained system. It's
the LEGO NXT and I have about 52K of RAM allocated to
the heap, which is controlled by malloc()

Once I've loaded the API for the NXT peripherals (C binding to Lua)
the gcinfo() tells me I have about 16K left - which I find hard
to believe. There are about 40 calls to C functions.

What can I tune in the source to force the gc to be more
aggressive, and can it work if I give it a fixed block of
memory that can never be expanded?

Also, can I force the gc to run during script evaluation?

Sometimes if a script is large or complex, the malloc()
I have simply bails and dies saying it can't allocate
any more memory.

Cheers, Ralph

Reply | Threaded
Open this post in threaded view
|

Re: Garbage Collector on Constrained System

Rici Lake-2
Glenn Edgar Admin wrote:
I have the same problem. I have to be agressive about forcing the garbage collector during loops. When newbe's run lua for the first time on embedded systems, they have the same problem, even on heaps in the mega bytes. ( They run over night tests.) Lua gets a black eye because they think is memory leaks inside the engine, and I have to do a song and dance to smooth out the situation.

I thought about changing it, but in my line of work it is important not to touch the baseline and only extend and embedded.

Glenn Edgar

On 3/22/07, * Ralph Hempel* <[hidden email] <[hidden email]>> wrote:

    I've got a bit of a problem that I hope some gurus can
    help me out with.

    I'm running 5.1.1 on a very memory constrained system. It's
    the LEGO NXT and I have about 52K of RAM allocated to
    the heap, which is controlled by malloc()

    Once I've loaded the API for the NXT peripherals (C binding to Lua)
    the gcinfo() tells me I have about 16K left - which I find hard
    to believe. There are about 40 calls to C functions.

    What can I tune in the source to force the gc to be more
    aggressive, and can it work if I give it a fixed block of
    memory that can never be expanded?

    Also, can I force the gc to run during script evaluation?

    Sometimes if a script is large or complex, the malloc()
    I have simply bails and dies saying it can't allocate
    any more memory.

    Cheers, Ralph

You can tune the garbage collector as described in the reference manual:
http://www.lua.org/manual/5.1/manual.html#pdf-collectgarbage

The key settings are setpause and setstepmul; I've found that in tight loops with a lot of allocation of small objects (usually strings) and where there are large tables of static reference data, you need to make the garbage collector more aggressive; some experimentation may be necessary to come up with a better tuning in your environment. Generally, I adjust the pause to between 150 and 175, instead of the default 200, but even smaller values are plausible. (Those are percentages, so 200 actually means 2.0).

The consequence of basing the gc's behaviour on the amount of memory actually used is that gc tuning can be suboptimal if there is a lot of static data; transient objects can pile up until they reach the size of the used heap at the end of the previous gc cycle (by default). So if you have 128 megabytes of stuff which never changes, gc will be deferred at the end of every gc cycle until 128 megabytes of transient objects have built up. At that point it will start collecting garbage at a rate roughly approximating twice the allocation rate (by default), but if the allocations are smallish, quite a few can build up before each gc step, and in extreme cases, memory usage can even continue to increase for a while. In some ways, it might be better if there a way of setting an expected heap floor, to compensate for such situations, so that the pause would be based on a formula like p * (usage - floor) instead of just p * usage. That might be even harder to tune, though.





Reply | Threaded
Open this post in threaded view
|

Re: Garbage Collector on Constrained System

Ralph Hempel
Rici Lake wrote:

You can tune the garbage collector as described in the reference manual:
http://www.lua.org/manual/5.1/manual.html#pdf-collectgarbage

I read this first, and have some confusion. As I understand it, the
setpause tells the garbage collector to run when the current memory
usage is some percentage of the usage the last time the collector ran.

The default of 200% (2) means memory use has to double before the
collector runs, which is fine if you have a huge heap. On my system
with 52K of heap, if I was using 26K the last time the collector
ran, it would not run again until I was out of memory.

The key settings are setpause and setstepmul; I've found that in tight loops with a lot of allocation of small objects (usually strings) and where there are large tables of static reference data, you need to make the garbage collector more aggressive; some experimentation may be necessary to come up with a better tuning in your environment. Generally, I adjust the pause to between 150 and 175, instead of the default 200, but even smaller values are plausible. (Those are percentages, so 200 actually means 2.0).

I am using 110 for now, so I'm on the right track, even if it's very
aggressive.

The consequence of basing the gc's behaviour on the amount of memory actually used is that gc tuning can be suboptimal if there is a lot of static data; transient objects can pile up until they reach the size of the used heap at the end of the previous gc cycle (by default). So if you have 128 megabytes of stuff which never changes, gc will be deferred at the end of every gc cycle until 128 megabytes of transient objects have built up. At that point it will start collecting garbage at a rate roughly approximating twice the allocation rate (by default), but if the allocations are smallish, quite a few can build up before each gc step, and in extreme cases, memory usage can even continue to increase for a while. In some ways, it might be better if there a way of setting an expected heap floor, to compensate for such situations, so that the pause would be based on a formula like p * (usage - floor) instead of just p * usage. That might be even harder to tune, though.

Agreed. I'll keep using the aggressive settings and think about ways to
force GC to happen more frequently.

Thanks for the ideas,

Ralph