Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
Is it "safe" to exit a subroutine while in a While/Wend loop inside the Sub, or does this cause problems with things like the Stack or "memory leak" etc?
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
SUBs are fine to exit. (We even have an EXIT SUB command for them. https://qb64phoenix.com/qb64wiki/index.php/EXIT)
GOSUBs could end up presenting an issue for you, if you run around exiting them without returning, however, so you might want to be careful with them if you make use of them in your code.
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
Thanks Steve.
I was aware of the Exit Sub command, and use it often. It's just when I want to exit a loop AND the sub, that worries me. I can do this in two steps, by exiting the While, then having a provisional exit from the sub, but I wanted to simplify the operation. It sounds like I'll have to do this, for stability.
Posts: 276
Threads: 14
Joined: Apr 2022
Reputation:
27
I've had no issues with EXIT SUB within a loop structure in the SUB, just so long as you're sure that you're done with all SUB operations.
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
02-02-2023, 11:09 PM
(This post was last modified: 02-02-2023, 11:10 PM by PhilOfPerth.)
@OldMoses: Thank for that.
I've used it before too, without any issues that I'm aware of.
I intend to do some testing to see if repeated use will cause problems or not, so then I'll feel safer.
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
02-02-2023, 11:48 PM
(This post was last modified: 02-02-2023, 11:51 PM by PhilOfPerth.)
Here's a small test I've just run, which runs a snippet that calls a sub 10000 times, and exits early each time:
Code: (Select All) Screen 9
For runs = 1 To 100000 ' run the prog 10000 imes
Numbers:
For num = 1 To 10
Print num; ' print numbers 1 to 10
Next
letters ' now call the letters sub
Print
Print "Run #"; runs; "finished": Print ' show how many runs completed
Next
Print: Print "The final run should yield the same result as the first:"
Print " 1 2 3 4 5 6 7 8 9 10 ABCDEFGHIJ"
Sub letters
letrnum = 0
While letrnum < 26 ' repeat this loop 26 times
letr$ = Chr$(letrnum + 65) '
If letrnum = 10 Then Exit Sub ' Bail out early, after j
Print letr$; ' show letter A, then B etc until Z
letrnum = letrnum + 1 ' next letter
Wend
_Delay .1
End Sub
There was no change in the output, so I assume there was no corruption caused by the early exit. Is this a reasonable assumption?
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
02-03-2023, 12:04 AM
(This post was last modified: 02-03-2023, 12:04 AM by SMcNeill.)
Aye. As I mentioned previously, exiting from a SUB has zero bad repercussions.
Unless...
Code: (Select All) SUB foo
FOR i = 1 to 100
GOSUB fooGosub
NEXT
EXIT SUB
fooGosub:
PRINT i
IF i = 10 THEN EXIT SUB
RETURN
END SUB
Now, in the above, you're going to have issues eventually, and some folks would say "SEE?!! YOUR EXIT SUB EXPLODED THE PROGRAM!!!" -- which isn't *actually* the issue. The problem is you used an EXIT SUB to exit the sub WITHOUT returning from the GOSUB first. It's the GOSUB and the lost RETURN which is the true problem, and not the EXIT SUB, but it's still something to know to watch out for, if you ever use the routines in combination like that.
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
02-03-2023, 12:56 AM
(This post was last modified: 02-03-2023, 12:57 AM by PhilOfPerth.)
(02-03-2023, 12:04 AM)SMcNeill Wrote: Aye. As I mentioned previously, exiting from a SUB has zero bad repercussions.
Unless...
Code: (Select All) SUB foo
FOR i = 1 to 100
GOSUB fooGosub
NEXT
EXIT SUB
fooGosub:
PRINT i
IF i = 10 THEN EXIT SUB
RETURN
END SUB
Now, in the above, you're going to have issues eventually, and some folks would say "SEE?!! YOUR EXIT SUB EXPLODED THE PROGRAM!!!" -- which isn't *actually* the issue. The problem is you used an EXIT SUB to exit the sub WITHOUT returning from the GOSUB first. It's the GOSUB and the lost RETURN which is the true problem, and not the EXIT SUB, but it's still something to know to watch out for, if you ever use the routines in combination like that.
Sorry, Pete, I think I missed the point (yes, I'm a bit dense), but I ran your sub foo 10000 times (from a loop) and it executed as I expected - counted and displayed 1 to 10, then, from my loop, repeated this flawlessly and without throwing an error.
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
02-03-2023, 02:13 AM
(This post was last modified: 02-03-2023, 02:17 AM by SMcNeill.)
After 1 minute:
After a few minutes:
And after another small wait:
Now, what's our memory usage look like in those various screenshots? See the issue now?
Exiting a GOSUB without a corresponding RETURN is a memory leak. Eventually it's going to add up and cause you issues in one form or another.
Seems the website that hosts our screenshots and images is currently not working. If you try the code below and watch your task manager, you can see the endless cimb of memory.
Code: (Select All) DO
foo
LOOP
SUB foo
FOR i = 1 TO 100
GOSUB fooGosub
NEXT
EXIT SUB
fooGosub:
PRINT i
IF i = 10 THEN EXIT SUB
RETURN
END SUB
We start at 60MB of ram usage, then go up to 100MB and then keep climbing to 200MB, and then keep going up, up, and up endlessly until the program crashes or you start using swap file memory and writing to your hard drive... until your drive is full and THEN the whole OS probably freezes and crashes....
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
02-03-2023, 02:40 AM
(This post was last modified: 02-03-2023, 02:52 AM by PhilOfPerth.)
(02-03-2023, 02:13 AM)SMcNeill Wrote: After 1 minute:
After a few minutes:
And after another small wait:
Now, what's our memory usage look like in those various screenshots? See the issue now?
Exiting a GOSUB without a corresponding RETURN is a memory leak. Eventually it's going to add up and cause you issues in one form or another.
Seems the website that hosts our screenshots and images is currently not working. If you try the code below and watch your task manager, you can see the endless cimb of memory.
Code: (Select All) DO
foo
LOOP
SUB foo
FOR i = 1 TO 100
GOSUB fooGosub
NEXT
EXIT SUB
fooGosub:
PRINT i
IF i = 10 THEN EXIT SUB
RETURN
END SUB
We start at 60MB of ram usage, then go up to 100MB and then keep climbing to 200MB, and then keep going up, up, and up endlessly until the program crashes or you start using swap file memory and writing to your hard drive... until your drive is full and THEN the whole OS probably freezes and crashes....
Ahah, got it!
CPU usage stays the same, but memory used climbs, presumably to crash at some stage.
But I think I'm still ok to exit early if no other calls are involved, i.e. the sub has not called another sub or process that's still active?
Wrong! I see it still creeps up in my example.
I guess I'll have to be careful how I exit. Thanks.
|