gopher-lua
gopher-lua copied to clipboard
LState memory tracking feature
- [X] GopherLua is a Lua5.1 implementation. You should be familiar with Lua programming language. Have you read Lua 5.1 reference manual carefully?
- [X] GopherLua is a Lua5.1 implementation. In Lua, to keep it simple, it is more important to remove functionalities rather than to add functionalities unlike other languages . If you are going to introduce some new cool functionalities into the GopherLua code base and the functionalities can be implemented by existing APIs, It should be implemented as a library.
Please answer the following before submitting your issue:
- What version of GopherLua are you using? : 1cd887cd
- What version of Go are you using? : 1.13.1
- What operating system and processor architecture are you using? : darwin/amd64
- What did you do? : N/A
- What did you expect to see? : N/A
- What did you see instead? : N/A
I am interested in limiting the amount of memory used by individual LState
s, so that lua scripts with leaks in them cannot completely consume all process memory. It would be great to discuss some ideas here. At the end of this process I can potentially propose a patch.
My thoughts so far:
It is unlikely that we can get an exact measure of memory used by LState
s, the goal really is to total up the sizes of all LTable
s which are currently retained, and their contents. LTable
reference cycles should be handled and LTable
s which are global and local should be considered.
Passive tracking
Somehow keep a running approximation of the size of allocated memory. This would involve hooking code into table operations like RawSet
etc, table creation NewLTable
and possibly other points. Difficulties arise with tracking frees, as the GC nature of go means that we currently have no single point to hook when an LTable
is freed. (Go's finalizers are not helpful for data structures which can contain cycles). I think this could only be made to work if we stopped relying on GC to collect tables, and instead modified the VM to do explicit ref counting on table references - which would be too intrusive a change I think.
On demand calculation
Another approach could be to calculate the size of an LState
on demand - eg an ApproxMemSize
method for LState
. This method would iterate all values in the registry and the global table and sum their sizes - taking care to avoid double counting. This could be a relatively expensive operation, but it would have no runtime overhead to normal operation of the VM. It may be possible to do some caching between calls to ApproxMemSize
to try and skip sizing on tables which have not changed since the last call.
I'm interested in hearing any comments on these ideas or any alternative approaches - thanks!
I've managed to get a version of the "Passive Tracking" I proposed above working. For an individual LState
you can set a max number of tables, and a max number of total table keys (across all tables in the LState). If either is exceeded then the LState will raise an error. I managed to get it working using Go's finalizers so it is not a very intrusive change. I will test it for a while and then propose a PR in the new year.
Great work! I'm looking forward to seeing your PR.
PR open - please let me know if you have any feedback. I am running this code in production with no problems. Thanks!