Some of my scripts for daily use on a linux desktop

Thursday, January 13, 2011

Memory Leaks in Conky/Lua/Cairo

A user named "Creamy Goodness" of Nokia N900 phone uses conky on his phone and this phone does not have much memory. He looked at my scripts a little closer and gave me some pointers to reduce memory leaks :

1. Avoid global variables.
If you don't specify local in front of a variable, the variable is set to global. When conky runs the script, the global variable is set but it is not destroy at the end of the script (even if you set the variable to nil). At each loop a variable is created so memory usage increase !

But, it can be very interesting to have global variables with conky because each time a Lua script is called (ie at every update of the conky), the variable is still in memory and you can use it. This is the way I do when I draw graphs : the script start with an empty table and at each loop a new element popup the values in the table. Not very efficient but it works.

2. Declare variables in local
It's a good habit to declare variables in local, even in a local function, so they are destroyed when the script exits. I'm not sure but a local variable outside a function is OK too.

3. Don't forget "cairo_pattern_destroy"
When creating patterns, dont' forget to destroy them when the drawing is finished with cairo_pattern_destroy(pat) and of course destroy contexts and surfaces with cairo_destroy(cr) and cairo_surface_destroy(cs).

4. Use strict.lua to check use of undeclared variables
The script strict.lua can be found here or here or in the Lua5.1 package.
Creamy Godness made a modified version of this script to print a warning when it finds undeclared variables :
--
-- strict.lua
-- checks uses of undeclared global variables
-- All global variables must be 'declared' through a regular assignment
-- (even assigning nil will do) in a main chunk before being used
-- anywhere or assigned to inside a function.
--
-- From Lua distribution (etc/strict.lua)
--

local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget

local mt = getmetatable(_G)
if mt == nil then
mt = {}
setmetatable(_G, mt)
end

mt.__declared = {}

local function what ()
local d = getinfo(3, "S")
return d and d.what or "C"
end

mt.__newindex = function (t, n, v)
if not mt.__declared[n] then
local w = what()
if w ~= "main" and w ~= "C" then
print("assign to undeclared variable '"..n.."'")
end
mt.__declared[n] = true
end
rawset(t, n, v)
end

mt.__index = function (t, n)
if not mt.__declared[n] and what() ~= "C" then
print("variable '"..n.."' is not declared")
end
return rawget(t, n)
end


To use it, simply call the script in the script you want to check with
require 'strict'
if both scripts are in the same folder.

5. Workaround
You can use a cron job to run a script that will killall conky and restarts your conkys.


6. Further reading :
Lua documentation : Detecting Undefined Variables
The conky for the phone with the comments of Creamy Goodness, on Ubuntu Forums or on Mameo.org
Memory Leaks with Cairo and imlib2 on londonali's blog.

No comments:

Post a Comment