Fork me on GitHub
#clojure
<
2020-08-08
>
lilactown15:08:52

does anyone have any examples or guidance on hooking up a deftype to the GC? I want to detect when my object is collected so I can do some cleanup

lilactown15:08:23

I see that finalizers were deprecated in Java 9, which is unfortunate because it's about as much control as I want

lilactown15:08:36

(and effort lol)

potetm15:08:59

yeah finalizer is all I know

potetm15:08:13

but you really gotta question life decisions if you get there 😛

😄 3
vemv15:08:33

Yeah sounds like what a Component/Integrant stop method should do

lilactown15:08:34

in this case it's very much part of the domain I'm working in. I'm working on a general lib for creating reactive graph of objects; so I have references from node to node and back again. keeping references around after they can't be accessed anymore is no fun

lilactown15:08:24

I've already done the work of implementing simple reference counting so I can dispose of whole trees once they're explicitly cut off from the graph, the only issue is if a user loses access to a node then I don't have a way of detecting that it's been GC'd

lilactown15:08:30

the user can manually call a dispose function on it, which would probably be best practice, so my goal is just to do a best-effort attempt at cleaning up the graph when I detect a node has been GC'd

👍 3
vemv15:08:29

maybe your problem domain is loosely analog to Clojure's persistent data structures? Probably there are some interesting interactions between structural sharing and GC

lilactown15:08:04

IIRC Clojure's persistent data structures (and most data structures I would guess) only reference parent -> child

👀 3
lilactown15:08:53

this is nice(ish) for GC because once a parent is no longer referenced, then it can be GC'd, which will remove reference to the child, and so on

👍 3
lilactown15:08:53

in the case of my reactive graph, each node tracks not only other nodes it references, but also other nodes that reference it (a backwards reference). this way, when it's updated, it can tell nodes that are subscribed to it that it has been updated so they can recalculate their values.

lilactown15:08:32

this is bad for GC, because it means that even if a parent node is orphaned, it can't be cleaned up because of this circular reference

lilactown15:08:07

the way I'm handling it now is I have a special kind of node that can only contain forward references. So it can be GC'd. what I'd like to do is detect when those nodes are GC'd

lilactown16:08:43

hmm I would have to use weak references for all back refs then

phronmophobic16:08:21

yea. theres also a handful of other tools in that space, but they’re all kind of tricky. i think weakreference is the most straight forward. https://docs.oracle.com/javase/8/docs/api/java/lang/ref/package-summary.html#reachability has even more options

lilactown16:08:16

that seems pretty heavy weight for my case, since I'm already doing the work of reference counting internally so that I can stop propagating changes to nodes that aren't referenced any more

lilactown16:08:30

it would be much simpler (and probably more performant?) if I could tell when my output nodes have been GCd and call my own disposal method, rather than rely on GC to clean up all of my graph

phronmophobic17:08:19

makes sense. not sure what type of cleanup you need to do. the docs in java 9 for finalize point to cleaner and phantom reference which both seem interesting: • https://docs.oracle.com/javase/9/docs/api/java/lang/ref/Cleaner.htmlhttps://docs.oracle.com/javase/9/docs/api/java/lang/ref/PhantomReference.html

👀 3
lilactown15:08:07

the way I'm handling it now is I have a special kind of node that can only contain forward references. So it can be GC'd. what I'd like to do is detect when those nodes are GC'd

borkdude15:08:58

In a Clojure var, there is a boolean threadBound which is set to true in push-thread-bindings. When and where does that boolean return to the false state?

Alex Miller (Clojure team)15:08:20

Not looking at code, just guessing :)

Alex Miller (Clojure team)15:08:43

I think there is actually a jira about this

borkdude15:08:59

I guess the boolean should really be a counter?

borkdude15:08:44

to count the amount of thread-bindings that have been pushed and popped, and when it's back to zero, it's not threadBound anymore?

borkdude15:08:36

it seems that right now you're paying a small penalty for dynamic vars that have been bound once

borkdude15:08:46

if I understand the code correctly

borkdude15:08:15

This may be a good trade-off in general, since most vars aren't dynamic, so you don't have to bother with counters. Just not sure if that's the reasoning behind this.

borkdude15:08:34

I'm trying to optimize something in sci, which is why I was looking at this