Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak in implementation #2

Open
pauldix opened this issue Oct 19, 2018 · 7 comments
Open

Memory leak in implementation #2

pauldix opened this issue Oct 19, 2018 · 7 comments

Comments

@pauldix
Copy link
Owner

pauldix commented Oct 19, 2018

The Function and Environment structs in the object module reference each other and have circular references. I'm using Rc here to make things work, but I have to figure out a way to clean all these things up after calls to Monkey functions happen.

The Monkey language has closures which cause a new environment to be created for the function, but an outer environment to be referenced.

I'm not quite sure how to structure this to clean things up. In the book, Thorsten glossed over this and relied on Go's garbage collector to do the work. Does this mean that I'll have to implement a GC for the language to get all of this to work without memory leaks?

Without further reading and research I've hit the limits of my knowledge so any ideas or pointers would be greatly appreciated.

@Diggsey
Copy link

Diggsey commented Oct 22, 2018

From what I can tell the monkey language is garbage collected, and so you would need to implement a garbage collector/cycle detector in order to interpret it.

A simple GC should be easy for an interpreted language, as you should already know whats on the stack/in globals (the roots) and your data structures are easily traceable, so you just need to start from the roots, find everything reachable from them, and free anything you didn't encounter.

@boomshroom
Copy link

If you know you're going to be having back-pointers, I suggest taking a look at std::rc::Weak. Weak pointers allow access to a reference counted object without forcing it to stay alive, making them well suited for things like doubly-linked lists and parent pointers in a tree structure.

@pauldix
Copy link
Owner Author

pauldix commented Oct 22, 2018

@boomshroom I tried Weak at some point, but I had a tricky thing where I didn't have a least one strong reference so it dropped everything while the closure still needed to be around. I should take another look at that to see if I can make it work.

@Diggsey
Copy link

Diggsey commented Oct 22, 2018

Using Weak can't work in general for the language, because it has no clear ownership tree: functions own (should keep alive) their environment, and environments should own their functions. You can't even split them, because it's possible for functions to capture the same environment which owns them. You either have to introduce restrictions to the monkey language so that this is no longer possible, or implement some form of GC.

@kestred
Copy link

kestred commented Oct 23, 2018

A big rust contributor has recently been experimenting with garbage collected pointers written in rust--- it's not production ready yet; but if you can't use it directly it might at least provide inspiration.

It provides a Gc type which is a substitute for Rc in most cases.

Repo: https://github.com/withoutboats/shifgrethor
Blog: https://boats.gitlab.io/blog/post/shifgrethor-i/

@pandulaDW
Copy link

pandulaDW commented Nov 12, 2022

I recently finished implementing monkey in Rust myself as well. (https://github.com/pandulaDW/interpreter-in-rust). And from the look of it, I've taken an approach somewhat similar to yours. Sorry for my ignorance, but shouldn't the new environments that gets created during function calls be dropped at the end of each call evaluation?, which in turn would also drop the RC references attached to its outer environments?

@pauldix
Copy link
Owner Author

pauldix commented Nov 12, 2022

@pandulaDW It's been years since I thought about this code, but I think what I was referencing was that if you had a long running Monkey script, it would leak memory. If you just fire one-off Monkey scripts within a long running Rust process, then yes, that would be freed once the individual script invocation is done (I think).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants