gopher-lua icon indicating copy to clipboard operation
gopher-lua copied to clipboard

LState memory tracking feature

Open tul opened this issue 4 years ago • 3 comments

  • [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:

  1. What version of GopherLua are you using? : 1cd887cd
  2. What version of Go are you using? : 1.13.1
  3. What operating system and processor architecture are you using? : darwin/amd64
  4. What did you do? : N/A
  5. What did you expect to see? : N/A
  6. What did you see instead? : N/A

I am interested in limiting the amount of memory used by individual LStates, 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 LStates, the goal really is to total up the sizes of all LTables which are currently retained, and their contents. LTable reference cycles should be handled and LTables 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!

tul avatar Oct 15 '19 09:10 tul

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.

tul avatar Dec 23 '19 18:12 tul

Great work! I'm looking forward to seeing your PR.

yuin avatar Dec 25 '19 09:12 yuin

PR open - please let me know if you have any feedback. I am running this code in production with no problems. Thanks!

tul avatar Jan 07 '20 16:01 tul