Checking for low stock status on an independent thread within an
application.
Code -
METHOD cthread() CLASS MainScreen
LOCAL nID AS DWORD
LOCAL phandle AS PTR
phandle := CreateVOThread(NULL_PTR,0,@Checkstocksdis(),NULL_PTR,0,@nID)
RETURN NIL
FUNCTION Checkstocksdis()
LOCAL dbsvrS AS dbserver
LOCAL Firsttime := TRUE AS LOGIC
DO WHILE TRUE
Sleep(10000)
dbsvrS := DBSERVER{Batchingpath+prefix+"StkLvl.dbf",TRUE,FALSE}
IF dbsvrS:status = NULL_OBJECT
dbsvrS:gotop()
IF (dbsvrS:FIELDGET("Stkshow") != dbsvrS:FIELDGET("StkshowP")) .OR.
Firsttime
Firsttime := FALSE
IF dbsvrS:FIELDGET("Stkshow")
IF oBatchingScreen != NULL_OBJECT
oBatchingScreen:oDCFixedText3:show()
ENDIF
ELSE
IF oBatchingScreen != NULL_OBJECT
oBatchingScreen:oDCFixedText3:hide()
ENDIF
ENDIF
ENDIF
dbsvrS:close()
dbsvrS := NULL_OBJECT
ENDIF
Sleep(20000)
ENDDO
RETURN NIL
There is a memory leak there which doesn't happen if I don't run the thread.
What am I doing wrong? The thread gets created once in the application and
then runs during the duration of the application. Will this memory leak
cause the application to shut down spontaneously??
Thanks and regards,
Vaishali
Probably not the answer your looking for but if you change your code a bit you
need never open the DBServer at all
Eg
// Seeing as your only updating a FT on oBatchScreen there's absolutely no
reason to open the Server if it's NULL
IF oBatchingScreen != NULL_OBJECT
dbsvrS := DBSERVER{Batchingpath+prefix+"StkLvl.dbf",TRUE,FALSE}
IF dbsvrS:Used
// IF dbsvrS:status = NULL_OBJECT
dbsvrS:gotop()
// The field comparison is useless as FirstTime is always TRUE
IF (dbsvrS:FIELDGET("Stkshow") != dbsvrS:FIELDGET("StkshowP"))
.OR.Firsttime
// Useless bit of code as FirstTime isn't used after this
Firsttime := FALSE
IF dbsvrS:FIELDGET("Stkshow")
oBatchingScreen:oDCFixedText3:show()
ELSE
oBatchingScreen:oDCFixedText3:hide()
ENDIF
dbsvrS:close()
ENDIF
dbsvrS := NULL_OBJECT
ENDIF
HTH
Steve
Didn't quite understand how the server does not need to be opened at all
........if I don't open it, how do I check the status?
The field comparison is required as it is in a do while true loop - after
the first instance, it will encounter a Firsttime = FALSE. The field
comparison prevents the update if there is no change.
Other than that, do you see an evident error which might cause a leak?
Thanks and regards,
Vaishali
"Stephen Quinn" <stev...@SPbigpondAM.net.au> wrote in message
news:lDLfh.7232$HU....@news-server.bigpond.net.au...
From your code your only changing the status if
oBatchingScreen != NULL_OBJECT
so if it is (NULL) then there is NO reason to check any status as
oBatchingScreen doesn't exist.
If oBatchingScreen always exists then there is no need to check to see if it's
NULL.
If oBatchingScreen only exists sometimes (ie when the user opens a particular
window) then you should only be executing this thread when it does exist IMO not
for the duration of the apps existence.
> The field comparison is required as it is in a do while true loop - after the
> first instance, it will encounter a Firsttime = FALSE. The field comparison
> prevents the update if there is no change.
OK - missed the While TRUE bit<g>
> Other than that, do you see an evident error which might cause a leak?
Seeing as you've shown no code to close down the thread, how/when do you shut it
down??
If your terminating the thread elsewhere how can you be sure that the Server
isn't open at that point??
Can/does the thread terminate while it sleeps - Are you sure it can/does??
Could that be the reason why your leaking memory??
ie your not giving it time to clean up after itself
HTH
Steve
Got that now - the batching screen always exists - that check is probably
redundant - only prevents an error at app startup - and there probably is a
better way of doing it.
The thread exists as long as the application exists - it terminates with the
application.
I don't think the thread terminates while it sleeps. In any case, if I
removethe sleep statements, the leak occurs at approx. the same interval. -
4K at a time.
The memory leak is continuous so unlikely due to a lack of cleanup.
The code within the do while true statement seems (to me) fairly
straightforward and there doesn't seem to be an apparent reason for any
continuous memory allocation.
So am kind of well and truly stuck.
Thanks & regards,
Vaishali
"Stephen Quinn" <stev...@SPbigpondAM.net.au> wrote in message
news:BCMfh.7268$HU....@news-server.bigpond.net.au...
>>
I don't think the thread terminates while it sleeps. In any case, if I removethe
sleep statements, the leak occurs at approx. the same interval. -4K at a
time.
<<
I think you misunderstood me but if this is happening each time through the loop
then why not open the Server outside your loop and just test the status inside
the loop.
Eg
dbsvrS := DBSERVER{Batchingpath+prefix+"StkLvl.dbf",TRUE,FALSE}
IF dbsvrS:Used
dbsrvS:Gotop()
DO WHILE TRUE
Sleep(10000)
IF (dbsvrS:FIELDGET("Stkshow") != dbsvrS:FIELDGET("StkshowP")) .OR.
Firsttime
Firsttime := FALSE
IF dbsvrS:FIELDGET("Stkshow")
IF oBatchingScreen != NULL_OBJECT
oBatchingScreen:oDCFixedText3:show()
ENDIF
ELSE
IF oBatchingScreen != NULL_OBJECT
oBatchingScreen:oDCFixedText3:hide()
ENDIF
ENDIF
ENDIF
ENDDO
dbsvrS:close()
ENDIF
You still have the problem of closing the Server when you close your app, there
is NO code in here to check for thread termination, so it cannot clean up (ie
close the server) when it terminates (your in a do while true loop without any
exit stategy)
HTH
Steve
This is not a good use of threads. In fact, it's a terrible use <g>.
The way you implementing this mechanism gets nothing useful for the use
of the thread and only complicates everything else (and gives you all
this heart burn <g>). You have a very simple timer based checking
mechanism so this is very simply a timer based mechanism!
Use a timer on your oBatchingScreenWindow. Simple! Done...
1. no need for threads or their overhead
2. no GC problems
3. no need for globals
4. no need to test for existence
5. much less code
6. automatic destruction with the window
7. no need for expensive sleeps
8. automatic class references for controls and servers etc
In the window post init, set the timer with this:
DEFINE TIMER_CHECK_STOCK := 567889
SetTimer(SELF:Handle(), TIMER_CHECK_STATUS, 30000, NULL_PTR) // check
every 3 sec
In the Window close or destroy method you have this:
KillTimer(SELF:Handle(), TIMER_CHECK_STATUS)
Now, in your dispatch you have this:
CASE oEvent:wParam = TIMER_EVENT_EXECHECK
IF !oGlobal:UNATTENDED .and. !oGlobal:removealltimers
SELF:CheckStockStatus()
// or do all the processing right here!
ENDIF
So now you just use a method on the window class itself. (The global
stuff is just for demo) Isn't this a little more practical than what you
were trying?
Geoff
a) I have also found memory leaks with DBServer with memo-fields.
Does your server has a memo-field ???
b) You could change your code, and do not open this dbserver, but
instead read some registry-value. Just for test. Do you have memory
leaks in this way ? Maybe memory leak has nothing to do with the
dbserver, but with the screen.
c) Try the following: Do not use Show() or Hide(), but use direct
api-calls.
Dirk
> a) I have also found memory leaks with DBServer with memo-fields.
> Does your server has a memo-field ???
How so? We've never had any memory leaks from DBServers. Memo field or
not.
Geoff
I should have mentioned it earlier, but if I comment out the whole code and
just leave the sleep statements in, it has the same effect on memory.
This leads me to think that the problem is not with the server. I know it
sounds wierd but that is what happens. But will try that too again.
Thanks,
Vaishali
"Stephen Quinn" <stev...@SPbigpondAM.net.au> wrote in message
news:yeNfh.7284$HU....@news-server.bigpond.net.au...
Understand what you are saying. I have used the timer function in many
places before. Am not sure why I did not do it here.
But will do.....<g>
Thanks
Vaishali
"G Schaller" <geoff@soft_ware.com.au> wrote in message
news:457fa51d$1...@dnews.tpgi.com.au...
Yes, its a leak of about 24 bytes (VO25b3 and CDX-FPT), but before you
see 24 bytes, you have to do a big loop.
It is send to dev, but no reaction at all (like other db-stuff with no
reaction...
If you want, I can search my very old test leak app..
Dirk
Can you make a small app that proves this?
I'd like to take a look because I still don't believe you <g>.
(...and what's 24 bytes after a big loop???)
Geoff
"Dirk (Belgium)" <dirk.he...@pbprojects.be> wrote in message
news:ts22o2d87hkdb9466...@4ax.com:
It is 24 bytes for each loop !!
But how to see the leak of 24 bytes.
After running it 1000 times...
Dirk
On Thu, 14 Dec 2006 20:42:45 +0000, "G Schaller"
Collect forced
? dyn mem
For n = 1 upto 1000
Open server
Do stuff
Close server
Next
collectforced
? dyn mem
Maybe its not opening a server but merely accessing the memo field?
Dunno. You write the code and provide the dbf/cdx to go with it and I
will test it for you. BUT if there is a leak, this code will show it.
Geoff
"Dirk (Belgium)" <dirk.he...@pbprojects.be> wrote in message
news:2pm4o21qnudil9prc...@4ax.com:
> Yes, its a leak of about 24 bytes (VO25b3 and CDX-FPT), but before you
> see 24 bytes, you have to do a big loop.
> It is send to dev, but no reaction at all (like other db-stuff with no
> reaction...
I am not sure where you have send the memory leak example, but it is not in
our bug database on support.cavo.com., and you also did not send it to me.
I think it is also not fair to state here that you have had no reaction on
questions about db-stuff. I can remember that we had an extensive email
conversation a couple of months ago about the problems you have with
creating your own RDDs.
You even promised to send me the RDD, but I haven't heard from you since
then.
--
Robert van der Hulst
AKA Mr. Data
Vo2Jet & Vo2Ado Support
VO Development Team
www.heliks.nl
Indeed, it has something to do with the memo.
I write it a few messages ago !!!
Friday, I found my example back. I will install it first, and try out
your sample code to look to the leak.
Dirk
On Fri, 15 Dec 2006 09:18:14 +0000, "G Schaller"
I write "but I haven't heard from you since then.".
Indeed, it is not completely solved. The problem is the
AppendDB-method in the RDD Classes.
I have send you also this problem, also sven, and even Brian.
Even a guy who has access to VOPS has send this question to you,
but it seems that making a new VO with new editor etc.. is more
important then the resulting program written with VO.
But, OK, This week you will receive the RDD !!
Maybe that make you to decide to change AppendDB.
(And it is not so difficult, because I send already pieces of my code
to Brian for replacement of the AppendDB-method)
Dirk
The example with a DBFLeak is send to your private e-mail.
Please check.
Dirk
What's your email-adress ????
Please send me a simple email, which I can reply...
Dirk
On Fri, 15 Dec 2006 09:18:14 +0000, "G Schaller"
Got your sample - changed it run on my CDrive - and printed the
debugoutput messages instead of to the status bar and it is clean as a
whistle. No memory leak (Build 2756). Perfect.
Sorry for the bad news <g>.
Geoff
"Dirk (Belgium)" <dirk.he...@pbprojects.be> wrote in message
news:33nko2t57dufbd1cn...@4ax.com:
Dirk was using a timer and the statusbar to examine dyn mem usage in a
tight loop. This was always going to show the timer mem increments and
stuff for the status bar. I wrote him a plain loop only using debug
output strings - opening and closing the dbf 1000 times. Takes about 2
seconds. There is no leak.
Now the only difference between Dirk and myself is that I am using Build
2756 and I assume Dirk is on 2740. So unless there is some bug only in
2740, there is no leak.
Geoff
"Dirk (Belgium)" <dirk.he...@pbprojects.be> wrote in message
news:33nko2t57dufbd1cn...@4ax.com:
a) Like I wrote, it is not build 2740, but VO 2.5b-3
b) Like I also wrote, the leak is not inside VO(classes) but, i think,
inside the RDD-Drivers, and because they are written in C, dynamic
memory is not the problem !!! The problem is "Mem Usage" in the
"Windows Task Manager".
Dirk
VO 2.5! Sheesh! <g>
Get with the program, man! What is goodness name did I waste all that
time for you for? I missed that <g>. Look, my point is simple. There is
no leak I can detect in 2.7 (and I will say I never saw this leak in 2.5
either!) so there is nothing to talk about.
In any event, there is absolutely no use in talking about 2.5 because
there is no possibility that anything could be done about it even if
there was a problem. Nor should there be. 2.5 is old hat and no longer
managed. I don't believe you have a problem and you haven't proved it
yet but of course I cannot compile your test code in 2.5 and nor do I
want to.
I have one piece of simple advice. Upgrade your apps to 2.7
Cheers.
Geoff
"Dirk (Belgium)" <dirk.he...@pbprojects.be> wrote in message
news:736no21219bg5u5lg...@4ax.com:
Please, read my comments about dynamic memory, because it is NOT a
leak in dynamic memory, and the only memory you are looking to is this
kind of memory.
You have to use other tools to see this leak in the "windows memory".
Dirk
"Dirk (Belgium)" <dirk.he...@pbprojects.be> wrote in message
news:7tb4p25vvcs26pp1a...@4ax.com:
Yesterday tested on 2740 ( the latest public update) and also there
the "private bytes" are growing when testing with memo-fields, but
"private bytes" are not growing when testen with a dbf-file without a
memo-field.
Dirk
As I said to you by email, it is now too difficult to continue working
on this via this forum because you only see an app crash after 14 days
or so of continuous running. None of our apps are run 24/7 so I cannot
compare, except to say that I cannot detect your leak in my current
version.
I also think that as crude as it sounds, if your app only crashes once
in 14 days that you should schedule a restart every 7 days or so. If it
truly only crashes once in 14 days it could be a lot of things.
Cheers.
Geoff
"Dirk (Belgium)" <dirk.he...@pbprojects.be> wrote in message
news:sov6p2h59gb5jtveo...@4ax.com: