Garbage Collection Issues #55

Closed
opened 2019-10-06 18:23:25 +00:00 by Enyby · 4 comments
Enyby commented 2019-10-06 18:23:25 +00:00 (Migrated from github.com)

Everything related to garbage collection most often works in LuaJ, not like in Lua.

Lua has its own garbage collector, with its own rules. LuaJ uses the Java garbage collector in the implementation on which LuaJ is running (for example, Android will have its own garbage collector features).

Things that are directly or indirectly related to garbage collection:

  1. Metamethod "__gc" in metatables. At this moment, this feature in LuaJ it is not supported at all.
  2. Weak Tables. There may be differences in the operation algorithms.
  3. Coroutines. There may be differences in the operation algorithms.
  4. The collectgarbage method. Parameters, behavior, call results - can and will differ from Lua.
  5. Automatically close files during garbage collection. You should always keep an eye out for closing files yourself. Otherwise, it will be a drain of resources.
    On Windows, any open file creates a lock on renaming and moving the file. On Unix, no.
    Most Lua tests rely on the fact that files are closed during garbage collection.

Some things we can try to implement through finalizers in Java. But this is unreliable and depends on the implementation of the Java machine running LuaJ.
Some things cannot be implemented.

You better not rely on the garbage collector in any way.

Everything related to garbage collection most often works in LuaJ, not like in Lua. Lua has its own garbage collector, with its own rules. LuaJ uses the Java garbage collector in the implementation on which LuaJ is running (for example, Android will have its own garbage collector features). Things that are directly or indirectly related to garbage collection: 1. Metamethod "__gc" in metatables. At this moment, this feature in LuaJ it is not supported at all. 2. Weak Tables. There may be differences in the operation algorithms. 3. Coroutines. There may be differences in the operation algorithms. 4. The collectgarbage method. Parameters, behavior, call results - can and will differ from Lua. 5. Automatically close files during garbage collection. You should always keep an eye out for closing files yourself. Otherwise, it will be a drain of resources. On Windows, any open file creates a lock on renaming and moving the file. On Unix, no. Most Lua tests rely on the fact that files are closed during garbage collection. Some things we can try to implement through finalizers in Java. But this is unreliable and depends on the implementation of the Java machine running LuaJ. Some things cannot be implemented. You better not rely on the garbage collector in any way.
Enyby commented 2019-10-06 18:31:30 +00:00 (Migrated from github.com)

You must carefully monitor all opened files. Especially for those that are created implicitly.

For example, io.lines(file) will open the file for reading. Until you read the entire file and the iterator returns nil, the file will be open for reading.
If you do this in a loop and break the loop, you will have a resource leak. On Windows, you will still have a file lock, which you cannot remove until you terminate your process.

Therefore, it is better to avoid io.lines(file), and open the file yourself and then call file:lines(), since you can then close the file yourself, at any time.

You must carefully monitor all opened files. Especially for those that are created implicitly. For example, `io.lines(file)` will open the file for reading. Until you read the entire file and the iterator returns nil, the file will be open for reading. If you do this in a loop and break the loop, you will have a resource leak. On Windows, you will still have a file lock, which you cannot remove until you terminate your process. Therefore, it is better to avoid `io.lines(file)`, and open the file yourself and then call `file:lines()`, since you can then close the file yourself, at any time.
Enyby commented 2019-10-06 20:34:10 +00:00 (Migrated from github.com)

J2ME: No finalization. CLDC does not include the Object.finalize() method.
So you must track and close all files explicit. Or you get resource leak.

J2ME: No finalization. CLDC does not include the Object.finalize() method. So you **must** track and close all files explicit. Or you get resource leak.
Enyby commented 2019-12-15 19:18:30 +00:00 (Migrated from github.com)

There are some side-effects of garbage collection implementation in LuaJ.

1. The values ​​of local variables, after exiting the block, can remain on the stack, preventing garbage collection.
For example, if you have a code

do
	local t = {}
end
collectgarbage()

Table t will not be collected by garbage collection until the register on the stack is reused.

To ensure garbage collection you must use functions. Each function has its own stack and there are no problems with garbage collection.
For example:

;(function ()
	local t = {}
end)();
collectgarbage()

or set variables to nil before leave block:

do
	local t = {}
	t = nil
end
collectgarbage()

2. Cascading garbage collection for weak tables does not work.
for example

a = {}; setmetatable(a, {__mode = 'k'})
x = nil
;(function ()
	for i = 1, 10 do local n = {}; a[n] = {k = {x}}; x = n end
	collectgarbage()
	x = nil
end)();
collectgarbage()
assert(next(a) == nil)

In the original Lua, it will collect all the values ​​from the table, as they are cascade-related:
It is worth removing the link to the last element, as this leads to the removal of the penultimate element.
In LuaJ, this code will not work.
The last garbage collection will remove only the last item.
You will need to do multiple garbage collection for this to work.
In this example, 10 times.

However, the situation is complicated by the fact that garbage collection in Java is hint, not order.
And it is not executed immediately. Therefore, you cannot just call collectgarbage() 10 times in a loop.
You need to insert some delay in order for garbage collection to complete between calls.

There are some side-effects of garbage collection implementation in LuaJ. **1. The values ​​of local variables, after exiting the block, can remain on the stack, preventing garbage collection.** For example, if you have a code ``` do local t = {} end collectgarbage() ``` Table t will not be collected by garbage collection until the register on the stack is reused. To ensure garbage collection you must use functions. Each function has its own stack and there are no problems with garbage collection. For example: ``` ;(function () local t = {} end)(); collectgarbage() ``` or set variables to nil before leave block: ``` do local t = {} t = nil end collectgarbage() ``` **2. Cascading garbage collection for weak tables does not work. for example** ``` a = {}; setmetatable(a, {__mode = 'k'}) x = nil ;(function () for i = 1, 10 do local n = {}; a[n] = {k = {x}}; x = n end collectgarbage() x = nil end)(); collectgarbage() assert(next(a) == nil) ``` In the original Lua, it will collect all the values ​​from the table, as they are cascade-related: It is worth removing the link to the last element, as this leads to the removal of the penultimate element. In LuaJ, this code will not work. The last garbage collection will remove only the last item. You will need to do multiple garbage collection for this to work. In this example, 10 times. However, the situation is complicated by the fact that garbage collection in Java is hint, not order. And it is not executed immediately. Therefore, you cannot just call `collectgarbage()` 10 times in a loop. You need to insert some delay in order for garbage collection to complete between calls.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: open-autonomous-connection/luaj#55