Re: [Oorexx-devel] Memory leak (Re: A question (Re: Ad .local and/or monitor class

2022-07-20 Thread Rick McGuire
On Wed, Jul 20, 2022 at 12:35 PM Rony G. Flatscher 
wrote:

> On 20.07.2022 18:05, Rick McGuire wrote:
>
> When the instance is terminated, all object references are cleared out in
> case there might be a dangling reference to the instance object that might
> pin it in memory. This includes .local, which should not be pinned
> anywhere. I spent fair about of time recently tracing the termination code
> to fix #1734, so I know it's doing what it's supposed to be doing.
>
> I was going to suggest reverting your overrides before terminating the
> instance. A more appropriate way to do that is to call the destination
> method with no argument.
>
> Did that as the first strategy: calling destination until .nil gets
> returned and then placing back the destination right before it.
>
> The monitor maintains a queue of the destination objects, so this will pop
> your monitor off of the queue and revert to the previous destination.
>
> Yes. It is possible however that there are Rexx programmers who may put
> another destination on top of it (hence popping the destinations until
> getting to the very first one in the first attempts) hence using
> destination until .nil got returned. (Then changed the logic to simply
> remove the monitor objects from .local by replacing the monitor objects
> with new ones that got configured like in the beginning which seems to work
> as well.)
>
> The only other thing to comes to mind is that you are calling the
> terminate API on the wrong thread or in the wrong circumstances (e.g., on
> the correct thread but as the result of a callout from running oorexx
> code). I know you tried doing the second one once before. Are you checking
> the you are getting a true return value from the terminate call?
>
> Terminate() is defined to be void (from rexxapi.pdf):
>
> 1.17.187. Terminate
> This API is available in context Instance.
> // Method Syntax Form(s)
> context->Terminate();
> Terminates the current Rexx interpreter instance. Terminate() may only be
> called from the thread context that originally created the interpreter
> instance. This call will wait for all threads to complete processing before
> returning.
> Arguments
> None.
> Returns
> Void.
>
> When an instance gets created on the native side it will be stored in a
> structure together with its Java peer (a jobj) and the Java object
> representing the Rexx interpreter configuration used when creating the
> instance (a jobj). That structure then gets placed on a simply linked list
> on the native side. The Java side gets the context instance pointer
> returned as a string rendering.
>
> In the use case of termination the native side gets that string, turns it
> into a RexxInstance pointer and searches it in the linked list. If found it
> gets used for invoking Terminate(), if not, then a Java exception gets
> raised.
>
> At operating system thread in which Terminate() gets invoked: this is
> controlled by Java (in this case by the cleaner of PhantomReferences).
>
That is probably your problem. Terminate() is getting called on the wrong
thread so the instances are leaking. I've just been looking at the code,
and I believe it should be possible to terminate an instance from another
thread as long as there's nothing currently running on the initial thread.

Rick


>
> ---rony
>
>
> ___
> Oorexx-devel mailing list
> Oorexx-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/oorexx-devel
>
___
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel


Re: [Oorexx-devel] Memory leak (Re: A question (Re: Ad .local and/or monitor class

2022-07-20 Thread Rony G. Flatscher

On 20.07.2022 18:05, Rick McGuire wrote:
When the instance is terminated, all object references are cleared out in case there might be a 
dangling reference to the instance object that might pin it in memory. This includes .local, which 
should not be pinned anywhere. I spent fair about of time recently tracing the termination code to 
fix #1734, so I know it's doing what it's supposed to be doing.


I was going to suggest reverting your overrides before terminating the instance. A more 
appropriate way to do that is to call the destination method with no argument.


Did that as the first strategy: calling destination until .nil gets returned and then placing back 
the destination right before it.


The monitor maintains a queue of the destination objects, so this will pop your monitor off of the 
queue and revert to the previous destination.


Yes. It is possible however that there are Rexx programmers who may put another destination on top 
of it (hence popping the destinations until getting to the very first one in the first attempts) 
hence using destination until .nil got returned. (Then changed the logic to simply remove the 
monitor objects from .local by replacing the monitor objects with new ones that got configured like 
in the beginning which seems to work as well.)


The only other thing to comes to mind is that you are calling the terminate API on the wrong 
thread or in the wrong circumstances (e.g., on the correct thread but as the result of a callout 
from running oorexx code). I know you tried doing the second one once before. Are you checking the 
you are getting a true return value from the terminate call?


Terminate() is defined to be void (from rexxapi.pdf):

   1.17.187. Terminate
   This API is available in context Instance.
   // Method Syntax Form(s)
   context->Terminate();
   Terminates the current Rexx interpreter instance. Terminate() may only be 
called from the thread
   context that originally created the interpreter instance. This call will 
wait for all threads to
   complete processing before returning.
   Arguments
   None.
   Returns
   Void.

When an instance gets created on the native side it will be stored in a structure together with its 
Java peer (a jobj) and the Java object representing the Rexx interpreter configuration used when 
creating the instance (a jobj). That structure then gets placed on a simply linked list on the 
native side. The Java side gets the context instance pointer returned as a string rendering.


In the use case of termination the native side gets that string, turns it into a RexxInstance 
pointer and searches it in the linked list. If found it gets used for invoking Terminate(), if not, 
then a Java exception gets raised.


At operating system thread in which Terminate() gets invoked: this is controlled by Java (in this 
case by the cleaner of PhantomReferences).


---rony

___
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel


Re: [Oorexx-devel] Memory leak (Re: A question (Re: Ad .local and/or monitor class

2022-07-20 Thread Rick McGuire
When the instance is terminated, all object references are cleared out in
case there might be a dangling reference to the instance object that might
pin it in memory. This includes .local, which should not be pinned
anywhere. I spent fair about of time recently tracing the termination code
to fix #1734, so I know it's doing what it's supposed to be doing.

I was going to suggest reverting your overrides before terminating the
instance. A more appropriate way to do that is to call the destination
method with no argument. The monitor maintains a queue of the destination
objects, so this will pop your monitor off of the queue and revert to the
previous destination.

The only other thing to comes to mind is that you are calling the terminate
API on the wrong thread or in the wrong circumstances (e.g., on the correct
thread but as the result of a callout from running oorexx code). I know you
tried doing the second one once before. Are you checking the you are
getting a true return value from the terminate call?

Rick



On Wed, Jul 20, 2022 at 11:04 AM Rony G. Flatscher 
wrote:

> After further excessive (literally additional days of) debugging I can
> state that upon Rexx interpreter instance (RII) terminations using the
> native Terminate() API, ooRexx does not release/run the uninit methods of
> at least the monitored objects (ooRexx BSF objects) of the .local monitors!
>
> =
> Here the relevant parts after creating, using and Terminate() 1,000 RIIs:
>
> References from ooRexx objects (under the control of ooRexx), pinning Java
> objects:
>
> ... cut ...*RexxAnalyzeRegistry category=[[B]**- 
> RefCount: entries=[  **2 000**] | references: min=[1] max=[1] 
> avg=[  1,0] sum=[2 000]**- MemSize:  entries=[  2 
> 000] | references: min=[1] max=[1] avg=[  1,0] sum=[
> **2 000**]**RexxAnalyzeRegistry category=[[C]**- 
> RefCount: entries=[  **2 000**] | references: min=[1] max=[1] 
> avg=[  1,0] sum=[2 000]**- MemSize:  entries=[  2 
> 000] | references: min=[2] max=[2] avg=[  2,0] sum=[
> **4 000**]**RexxAnalyzeRegistry category=[[I]**- 
> RefCount: entries=[  **4 000**] | references: min=[1] max=[1] 
> avg=[  1,0] sum=[4 000]**- MemSize:  entries=[  4 
> 000] | references: min=[4] max=[4] avg=[  4,0] sum=[   
> **16 000**]**RexxAnalyzeRegistry category=[java.io.InputStreamReader]**   
>  - RefCount: entries=[  **1 000**] | references: min=[1] 
> max=[1] avg=[  1,0] sum=[1 000]**RexxAnalyzeRegistry 
> category=[java.io.PrintWriter]**- RefCount: entries=[  
> **2 000**] | references: min=[1] max=[1] avg=[  1,0] 
> sum=[2 000]*
>
> ... cut ...
>
> References from Java objects (under the control of BSF4ooRexx), pinning 
> ooRexx engines (REXX_ENGINE, REXX_SCRIPT_ENGINE) and ooRexx objects 
> (REXX_PROXY):
>
>
> org.rexxla.bsf.engines.rexx.RexxCleanupRef:
> RexxCleanupRef [2022-07-20 15:16:10.61300]
>  RefKind: Instances: Finalized: Not Yet Finalized:
> --
> [TEST]..: [   0] [   0] [   0]
> [REXX_ENGINE]...: [   1 002] [   1 000] [   
> 2][REXX_PROXY]: [   9 000] [   8 994] [   
> 6]
> [REXX_SCRIPT_ENGINE]: [   1 000] [ 999] [   1]
> --
> Totals..: [  11 002] [  10 993] [   9]
>
> ---
>
> Here the ooRexx objects referenced by BSF4ooRexx on the Java side (cf. 
> REXX_PROXY above):
>
> OREXX_REGISTRY related:
> OREXX_REGISTRY   ~items: 6
> OREXX_REGISTRY_REFCOUNTER~items: 6
>
> t_jsr223.rex: ooRexx 5.0.0 r12473 (17 Jul 2022) / BSF 641.20220717 / Java 
> 17.0.3.1 (released: 2022-04-22), 64-bit (amd64) / Windows 10.0.19043
>
> count_rexx_gc: [4] count_java_gc: [4]
>
> ... cut ...
>
> =
> Here the relevant parts after creating, using and Terminate() 1,000 RIIs,
> this time running the following Rexx program right before termination of a
> RII from the Java side:
>
>  ... cut ...
>* String rexxCode =   // reset .input, .output, .error, 
> .traceOutput, .debugInput to free BSF objects if any
> "  lDir = .local  -- get .local  ;\n" 
> +
> "  lDir['INPUT'  ]= .monitor~new(ldir['STDIN' ]) ;\n" 
> +
> "  lDir['OUTPUT' ]= .monitor~new(ldir['STDOUT']) ;\n" 
> +
> "  lDir['ERROR'  ]= .monitor~new(ldir['STDERR']) ;\n" 
> +
> "  lDir['TRA

[Oorexx-devel] Memory leak (Re: A question (Re: Ad .local and/or monitor class

2022-07-20 Thread Rony G. Flatscher
After further excessive (literally additional days of) debugging I can state that upon Rexx 
interpreter instance (RII) terminations using the native Terminate() API, ooRexx does not 
release/run the uninit methods of at least the monitored objects (ooRexx BSF objects) of the .local 
monitors!


=

Here the relevant parts after creating, using and Terminate() 1,000 RIIs:

   References from ooRexx objects (under the control of ooRexx), pinning Java 
objects:

   ... cut ...
   /RexxAnalyzeRegistry category=[[B]- RefCount: entries=[ //*2 000*//] | 
references: min=[ 1] max=[ 1] avg=[ 1,0] sum=[ 2 000]- MemSize: entries=[ 2 
000] | references: min=[ 1] max=[ 1] avg=[ 1,0] sum=[ //*2 
000*//]//RexxAnalyzeRegistry category=[[C]- RefCount: entries=[ //*2 
000*//] | references: min=[ 1] max=[ 1] avg=[ 1,0] sum=[ 2 000]- MemSize: 
entries=[ 2 000] | references: min=[ 2] max=[ 2] avg=[ 2,0] sum=[ //*4 
000*//]//RexxAnalyzeRegistry category=[[I]- RefCount: entries=[ //*4 
000*//] | references: min=[ 1] max=[ 1] avg=[ 1,0] sum=[ 4 000]- MemSize: 
entries=[ 4 000] | references: min=[ 4] max=[ 4] avg=[ 4,0] sum=[ //*16 
000*//]//RexxAnalyzeRegistry category=[java.io.InputStreamReader]- 
RefCount: entries=[ //*1 000*//] | references: min=[ 1] max=[ 1] avg=[ 1,0] 
sum=[ 1 000]//RexxAnalyzeRegistry category=[java.io.PrintWriter]- 
RefCount: entries=[ //*2 000*//] | references: min=[ 1] max=[ 1] avg=[ 1,0] 
sum=[ 2 000]/

   ... cut ...

   References from Java objects (under the control of BSF4ooRexx), pinning 
ooRexx engines (REXX_ENGINE, REXX_SCRIPT_ENGINE) and ooRexx objects 
(REXX_PROXY):


   org.rexxla.bsf.engines.rexx.RexxCleanupRef:
   RexxCleanupRef [2022-07-20 15:16:10.61300]
 RefKind: Instances: Finalized: Not Yet 
Finalized:
   
--
   [TEST]..: [   0] [   0] [   
0]
   [REXX_ENGINE]...: [   1 002] [   1 000] [   
2]
   [REXX_PROXY]: [ 9 000] [ 8 994] [ 6]
   [REXX_SCRIPT_ENGINE]: [   1 000] [ 999] [   
1]
   
--
   Totals..: [  11 002] [  10 993] [   
9]

   ---

Here the ooRexx objects referenced by BSF4ooRexx on the Java side 
(cf.REXX_PROXY  above):

   OREXX_REGISTRY related:
 OREXX_REGISTRY ~items: 6 OREXX_REGISTRY_REFCOUNTER~items: 6

   t_jsr223.rex: ooRexx 5.0.0 r12473 (17 Jul 2022) / BSF 641.20220717 / Java 
17.0.3.1 (released: 2022-04-22), 64-bit (amd64) / Windows 10.0.19043

   count_rexx_gc: [4] count_java_gc: [4]

   ... cut ...

=
Here the relevant parts after creating, using and Terminate() 1,000 RIIs, this time running the 
following Rexx program right before termination of a RII from the Java side:


 ... cut ...
   /String rexxCode = // reset .input, .output, .error, 
.traceOutput, .debugInput to free BSF
   objects if any " lDir = .local -- get .local ;\n" + " lDir['INPUT' ]= 
.monitor~new(ldir['STDIN'
   ]) ;\n" + " lDir['OUTPUT' ]= .monitor~new(ldir['STDOUT']) ;\n" + " 
lDir['ERROR' ]=
   .monitor~new(ldir['STDERR']) ;\n" + " lDir['TRACEOUTPUT']= .monitor~new(ldir['ERROR' 
]) ;\n" + "
   lDir['DEBUGINPUT' ]= .monitor~new(ldir['INPUT' ]) ;\n" ; /

Object obj=null;
try {
obj=rexxInterface.jniRexxRunProgram(
rii_ID, // RexxInstance instance ID
2,  // invocationType, // determines whether 
"CallProgram", "LoadPackage" or "LoadPackageFromData" is to be used

"RexxEngine_terminate_cleanup_local_monitors" ,   // fileName
/rexxCode /,  // Rexx code to execute
null// arguments
);
 }
 ... cut ...

 
res=rexxInterface.jniRexxTerminateInterpreterInstance(rii_ID);  // wait for 
termination of all Rexx threads of this interpreter instance

 ... cut ...

Doing this for every RII will cause the UNINIT method of the BSF objects to be run, correctly 
removing the pinned (peer) Java objects:


   References from ooRexx, pinning Java objects:

   ... cut ...
   /RexxAnalyzeRegistry category=[[B]- RefCount: entries=[ //*2*//] | 
references: min=[ 1] max=[ 1] avg=[ 1,0] sum=[ 2]- MemSize: entries=[ 2] | 
references: min=[ 1] max=[ 1] avg=[ 1,0] sum=[ 
//*2*//]//RexxAnalyzeRegistry category=[[C]- RefCount: entries=[ 
//*2*//] | references: min=[ 1] max=[ 1] avg=[ 1,0] sum=[ 2]- MemSize: 
entries=[ 2] | references: min=[ 2] max=[ 2] avg=[ 2,0] sum=[ 
//

Re: [Oorexx-devel] Ad debugging garbage collection dependent resources

2022-07-20 Thread Rony G. Flatscher

Dear P.O.,

On 20.07.2022 08:25, ooRexx wrote:
I assume this functionality can not be made a library (like orxutils et al) but need to be 
included in the build process, right? IF not included/accepted in the trunk I suggest you put all 
the necessary files in an entry under tools and document how to make it work. In this way anyone 
who wants to give it a try can do so without affecting the official builds.


Well, this would be some special location then, like "unaccepted, but useful" features and I would 
doubt that this was really helpful for anyone as a person needs to be aware of that. It is better 
not to make things more complicated.


As someone pointed out this seems to be a substantial effort and we should keep it in the SVN 
repository.


Well there was some effort to figure it out. The patch is actually rather short 
and simple.

Maybe I do the same as for the concurrent trace and file a RFE with the patch. This way the RFE is 
documented and whoever needs the patch can fetch and apply it from there.


There are situations (mostly debugging, but not only), where gc() is important, 
also for ooRexx.

---rony





On 16. Jul 2022, at 17:11, Rony G. Flatscher  wrote:

While debugging (for almost two months) ooRexx and BSF4ooRexx/Java it was almost impossible to 
determine the source of some memory leaks.


The reason was not being able to rely on the garbage collector having run at a specific point in 
time such that all objects that have no references anymore get garbage collected and if uninit 
methods present have them run. Only then would an analysis become really possible.


As it is possible with Java to kick the Java garbage collector in order to get at a stable state 
with regards to garbage collecting Java objects a gc() for ooRexx would make it possible to 
arrive at the same ability for ooRexx: to become able to arrive at a stable state at a certain 
point in time. Only then would it become possible to assess where the sources of memory leaks are 
rooted: on the ooRexx side or on the Java side.


Consider also the runtime dynamics in this context: there are cross calls/invocations, even on 
different ooRexx and on different Java threads at the same time (which all need to be 
controlled/synchronized while debugging).


In the end I created a gc() built in function in my "personal ooRexx interpreter" ;) to become 
able to debug ooRexx and Java/BSF4ooRexx to help identify all such locations and determine which 
side is responsible for keeping references that should have been freed. While debugging quite a 
lot of programs got created that would excercise gc() and java.lang.System.gc() allowing to 
determine the various sources of memory leaks (ooRexx and Java side) and thereby becoming able to 
address them and test the solutions. Again, without gc on the ooRexx side this would not have 
been possible!


---

For everyone who has such a need (to debug complex interactions with external function libraries 
with observed memory leaks) it is mandatory to have the ability in ooRexx available to kick off 
the ooRexx garbage collector to achieve a stable state.


Therefore proposing to add a gc() BIF (built-in-function) to ooRexx to enable debugging in such 
dynamic native peer systems/environments.


As any garbage collector run is relatively expensive it is necessary to warn any ooRexx 
programmer from using the gc() BIF in regular programs and make sure they only consider its use 
for debugging only. This may be achieved by creating a documentation that communicates this fact 
clearly/explicitly, maybe something along the lines:


"Warning: this function should only be used for developers who explicitly 
have a very special
need of debugging memory leaks with external function libraries!

Do not use this function in regular ooRexx applications as each explicit 
invocation of this
function is very expensive and may slow down the execution of your ooRexx 
application
considerably! 


This function will kick off the ooRexx garbage collector out-of-bounds and 
finalize all
objects that have no references at that particular point in time and run 
their uninit methods
if present.

Remark: the ooRexx garbage collector will get invoked by the interpreter at 
well defined
states and will thereby make sure that the programs will execute as 
efficiently as possible.
Therefore there is no need - other than for debugging - to explicitly 
invoke the garbage
collector out-of-bounds."

Of course, not being a native English speaker the above draft for the documentation text may need 
to be rephrased to be more clear. However, it should be clear for everyone that the ooRexx gc() 
BIF is not meant to be used for production.


---rony

___
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel


[Oorexx-devel] [Oorexx-svn] SF.net SVN: oorexx-code-0:[12476] main/trunk/interpreter

2022-07-20 Thread ooRexx
My initial mail bounced so I send it to the developers list

This change made one test fail in the SYMBOL testgroup (all platforms I think)

failure] 20220720 02:10:59.042803
  Test:   TEST_SYMBOL
  Class:  SYMBOL.testGroup
  File:   .../ooRexx/base/bif/SYMBOL.testGroup
  Line:   144
  Failed: assertEquals
Expected: VAR
Actual:   LIT

This line

self~assertEquals('VAR', SYMBOL('J’))

Should probably be changed to 

self~assertEquals(‘LIT', SYMBOL('J’))


Hälsningar/Regards/Grüsse,
ooRexx
oor...@jonases.se



___
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel