Lua - Memory Management



Lua provides automatic memory management and objects if not referenced or are referenced by weak references as mentioned in a weak table, are collected by garbage collectors.

Although Lua does most of the boilerplate code for memory management, developers are still open to do memory management to increase efficiency of the programs with the help of weak tables as we discussed in Weak Tables chapter and memoize function technique. In this chapter, we're going to discuss memoize function technique in details.

Memoize Functions

It is often useful to remember output of a function for certain parameters. It is a kind of caching which although simple by concept but it very powerful technique. For example, whenever a server is accepting a request, it has to make a database operation for the user details. Now if same user is making requests, we can remember the details of the user in an auxiliary table. Whenever a request comes, we can check if entry of the user is already present in the table or not and instead of making a database call, we can return the user details from the auxiliary table.

-- auxiliary table for caching purpose
local users = {}

-- function to memoize user
function mem_user (userId)
   -- if user details are present in auxiliary table
   if users[userId] then      
      -- reuse the user details  
      return users[userId]     
   else
      -- make the time expensive call    
      local userDetails = loadUserFromDatabase(userId) 
      -- save the user for later reuse	  
      users[userId] = userDetails            
      return userDetails
   end
end

Problem with memoize function

Now if we keep accumulating details in auxiliary table and in case of very large number of requests, server memory may get depleted. It may happened that few entries are not used much and memory can be reclaimed. But being in table, those entries can not be reclaimed.

Solution

We can use Weak table concept and mark the key and values of the auxiliary table as weak so that garbage collector can reclaim the memory.

-- auxiliary table for caching purpose
local users = {}

-- make the auxiliary table a weak table of weak values
setmetatable(results, {__mode = "v"}) 

-- function to memoize user
function mem_user (userId)
   -- if user details are present in auxiliary table
   if users[userId] then      
      -- reuse the user details  
      return users[userId]     
   else
      -- make the time expensive call    
      local userDetails = loadUserFromDatabase(userId) 
      -- save the user for later reuse	  
      users[userId] = userDetails            
      return userDetails
   end
end
Advertisements