Re: PilBox & Java object lifecycle
On Sat, Aug 26, 2023 at 11:56:42AM -0400, Todd Coram wrote: > Of course, tracking every object instantiation that gets stuffed into the > HashArray isn't trivial, The opposite (i.e. which objects are still referenced from Lisp) is easy though: (filter '((Obj) (== 32769 (car (id Obj T (all 0) ) This returns a List of all accessible Java objects. > It seems that any object returned by a Java method call is subject to be > placed > there so calls like (java (java someobject 'getResultingObject) 'doSomething)) > will place the inner object in the HashArray, correct? Yes. The call inserts the result of (java someobject ...) into the hashmap, and perhaps also the result of the outer 'java' call if it is an object. For example, : (java "java.io.File" T "name") -> {H@@@10327432} inserts *one* new object. If that object's internals are accessed, for example by : (show @) {H@@@10327432} ({H@@@751603011} . "java.io.File") filePath NIL path "name" prefixLength 0 status NIL fs {H@@@1172500016} pathSeparator ":" pathSeparatorChar 58 separator "/" separatorChar 47 serialVersionUID 301077366599181567 -> {H@@@10327432} then also all objects referred by it (i.e. {H@@@751603011} and {H@@@1172500016} will be inserted. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: PilBox & Java object lifecycle
On Fri, Aug 25, 2023, at 3:52 AM, Alexander Burger wrote: > and did some test. Works fine, and gives - as expected - a null pointer > exception if the object is accessed from Lisp again. Great! I've got same results here. Of course, tracking every object instantiation that gets stuffed into the HashArray isn't trivial, but for my purposes it's essential. It seems that any object returned by a Java method call is subject to be placed there so calls like (java (java someobject 'getResultingObject) 'doSomething)) will place the inner object in the HashArray, correct? I've taken to not doing nested (java) calls to manage this. And I've also wrapped a catch around my releases (java NIL obj) in case it has been release already from the HashArray... Some good idioms will need to go with the use of (java NIL...) > I cannot make a release to PlayStore now, as PilBox is in the process of some > changes to prepare for Android 14. So I made a temporary release available at: > >https://picolisp.com/pub/pilBox.apk >https://picolisp.com/pub/PilBox.tgz Thanks! I'll grab it soon. > Thanks a lot for the good idea! :) Thanks for validating it. My app has now been running over 24 hours (collecting BLE scans) without running out of memory (up from the 1-2 hour runs before). /todd -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: PilBox & Java object lifecycle
Hi Todd, > Perhaps something like: > (java NIL 'obj) for removing it from the hashtable? The "complex management" > of this could then be handled in pure Picolisp... Very good idea! This fits nicely into the 'java' syntax, and has no harmful effects if used wisely ;) > Would it be as simple as something like (in Reflector.java reflect()): >if (y == InOut.Nil) { // Release > reference to Object > Object o = lst[1]; // object to > release > int idx = o.hashCode(); > InOut.Obj.remove(idx); > Io.Out.write(InOut.NIX); > Io.Out.write(InOut.NIX); > x = null; > > Or am I heading in the wrong direction? No, this is basically correct. The write's are not needed, as they happen at the end of reflect() anyway. So I inseted: 1c1 < // 31jul23abu --- > // 25aug23abu 58a59 >// (java NIL 'obj) -> NIL Release reference to object 120c121,125if (y == InOut.Nil) { // Release reference to object > InOut.Obj.remove(lst[1].hashCode()); > x = null; >} >else if (y == InOut.T) { // Define interface and did some test. Works fine, and gives - as expected - a null pointer exception if the object is accessed from Lisp again. I cannot make a release to PlayStore now, as PilBox is in the process of some changes to prepare for Android 14. So I made a temporary release available at: https://picolisp.com/pub/pilBox.apk https://picolisp.com/pub/PilBox.tgz Thanks a lot for the good idea! :) ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: PilBox & Java object lifecycle
Hi Alex, Fantastic language (Picolisp) and very, very useful port to Android. On Thu, Aug 24, 2023, at 2:15 PM, Alexander Burger wrote: > Is this is really the cause of the problem? Most java calls do not make a new > object each time, and stored in the hash map are not all involved objects, but > only those which are reflected back to Lisp (and not all created internally). TBH, most of my troubles came from using the Android JSON library (which requires me to explicitly create the Java objects to add) and I do plan to move to a pure Picolisp implementation. But it did get me thinking about everywhere I instantiate a Java object via (java "classname" T). > The objects in the hash map are indeed never removed. This would be difficult > to > implement, because the Java side has no information about which objects are > still in use on the Lisp side. I'm pushing PilBox to the limits of (probably) what you intended: I want to run a minimal UI background service that scans BLE. It works well, but I'd like to keep track of the Java objects, even if done explicitly. With that said, there are occasionally instantiated objects I'd like to keep track of and don't mind house cleaning. I could even imagine instrumenting something handled in catch clauses or loop/function exit situations. I just need access to that hashtable. > Perhaps we can come up with ideas how to improve the situation. > Perhaps something like: (java NIL 'obj) for removing it from the hashtable? The "complex management" of this could then be handled in pure Picolisp... Would it be as simple as something like (in Reflector.java reflect()): if (y == InOut.Nil) { // Release reference to Object Object o = lst[1]; // object to release int idx = o.hashCode(); InOut.Obj.remove(idx); Io.Out.write(InOut.NIX); Io.Out.write(InOut.NIX); x = null; Or am I heading in the wrong direction? /todd -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: PilBox & Java object lifecycle
Hi Todd, > I have a long running PilBox Android app that tends to just "crash" (with a > "Webpage not Available... net:ERR_CONNECTION_REFUSED") after running for a few > hours. At this point, the REPL is unresponsive at this point and nothing is in > the PilBox log file. I need PilBox open all day for various reasons, and monitor it constantly. So I notice quickly if something goes wrong. In fact it crashes sometimes, but it is usually longer than a few hours (more like about once or twice a week). Typical crashes are usually not PilBox's fault. Android is a nasty host system, it kills apps whenever it feels it needs memory (kills with -9, not -15 !!!). Other situations are when Android updates system components in the background (most notably the System WebView), then PilBox is also killed. But: In most of the above cases, there is no connection error, but PilBox "resets", i.e. it goes to the home screen and lost its context. Technically, this means a new instance of the internal PicoLisp process was started. If you see the above connection errors, it seems that the PicoLisp process is gone and not restarted. Not sure. Also you probably know that you can force a full stop of PilBox and PicoLisp by swiping it off. This stopping did not work reliable in older PilBoxes and was improved a few months ago. BTW, do you use a current version of PilBox? Latest official release was 23.7.13 (183) > My app makes heavy use of Java calls (dozens every 5 seconds) and this got me > wondering about how PilBox treats the Java object life-cycle. A valid question. > I don't see clearly how the Java objects themselves are referenced so as not > to > be collected by the Java GC. I do see a static HashMap in InOut.java. Are Java > objects "put" there to save them from the GC? Yes, this is exactly the reason. > If so, when are they removed from the HashMap? I don't see any "remove" in > InOut.java or other PilBox Java sources. > > If objects are referenced there Is it possible that these objects are never > freed? > ... 2nd mail > I should be a little clearer: I "instantiate" dozens Java object every 5 > seconds > and wonder how Pilbox affects their life-cycle I understand the question well. And was aware of the trade offs from early on. The objects in the hash map are indeed never removed. This would be difficult to implement, because the Java side has no information about which objects are still in use on the Lisp side. Is this is really the cause of the problem? Most java calls do not make a new object each time, and stored in the hash map are not all involved objects, but only those which are reflected back to Lisp (and not all created internally). And: The objects in the hash map are truly minimal. They have no local data, they are just stubs. They seem big when looked at with (show Obj), but all these data are generated on the fly via reflection and not part of the objects themselves. Still, you are right that this mechanism will use more and more memory. Have you checked it? I did occasionally, using something like this code in the REPL: (let R (java "java.lang.Runtime" 'getRuntime) (java R 'gc) (let (Fmt (-7 9) Mem (java R 'totalMemory) Free (java R 'freeMemory) ) (tab Fmt "Total" (format Mem 3 "." ",")) (tab Fmt "Free" (format Free 3 "." ",")) (tab Fmt "Used" (format (- Mem Free) 3 "." ",")) ) R ) Perhaps we can come up with ideas how to improve the situation. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: PilBox & Java object lifecycle
I should be a little clearer: I "instantiate" dozens Java object every 5 seconds and wonder how Pilbox affects their life-cycle /todd On Thu, Aug 24, 2023, at 12:42 PM, Todd Coram wrote: > Hi, > I have a long running PilBox Android app that tends to just "crash" > (with a "Webpage not Available... net:ERR_CONNECTION_REFUSED") after > running for a few hours. At this point, the REPL is unresponsive at > this point and nothing is in the PilBox log file. > > My app makes heavy use of Java calls (dozens every 5 seconds) and > this got me wondering about how PilBox treats the Java object > life-cycle. > > I don't see clearly how the Java objects themselves are referenced so > as not to be collected by the Java GC. I do see a static HashMap in > InOut.java. Are Java objects "put" there to save them from the GC? If > so, when are they removed from the HashMap? I don't see any "remove" > in InOut.java or other PilBox Java sources. > > If objects are referenced there Is it possible that these objects are > never freed? > > /todd > > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe