| Todd Kreuter 2005-04-04, 8:03 pm |
| Lately I have seen more than a few posts related to forms not releasing
from memory, queries not closing, etc. When a form is closed, all
objects including data objects contained by the form should release
automatically provided no reference to the form remains in scope. Brute
force code to release or deactivate objects is not necessary. Your
primary concern should destroying any form reference you have created.
Following are a couple simple examples:
*- Example 1
local f
f = new SomeForm()
f.open()
In Example 1, as soon as the reference "f" is out of scope (which is
immediately after the procedure runs), closing the form should release
the form from memory.
*- Example 2
local f
f = new someForm()
_app.form = f
f.timer.parent = f
f.rowset.form = f
f.open()
In Example 2, closing the form will not release the form from memory
because references to the form remain in scope (the ones we created). We
must take care of the references we create to get rid of the form.
Function Form_onClose
_app.form = null
this.timer.parent = null
this.rowset.form = null
Following my signature is a working example of a form that will not
release when closed because of a reference to the form I create for a
timer object. Run the form multiple times as is and see what happens.
Then restart dBASE, open the form in the source editor and un-comment
out the line nulling out the timer.parent. Run the form again and
again...
This example uses some custom form code that checks the number of
instances in memory each time the form opens. I would recommend to
anyone, whether you think you have this problem or not <g>, that you
consider including this in your custom forms. This way you will know
when you have a problem.
--
Todd Kreuter [dBVIPS]
*** Copy and Paste to one file ***
** END HEADER -- do not remove this line
//
// Generated on 03/23/2005
//
parameter bModal
local f
f = new TimerForm()
if (bModal)
f.mdi = false // ensure not MDI
f.readModal()
else
f.open()
endif
class TimerForm of TESTCFORM
with (this)
onOpen = class::ONOPEN
onClose = class::ONCLOSE
height = 200.0
left = 0.0
top = 0.0
width = 200.0
text = "Timer Test"
endwith
this.ENTRY1 = new ENTRYFIELD(this)
with (this.ENTRY1)
height = 22.0
left = 21.0
top = 77.0
width = 140.0
value = "Entryfield1"
endwith
function onOpen
this.timer = new Timer()
this.timer.parent = this
this.timer.onTimer = class::onTimer
this.timer.interval = 1
this.timer.enabled = true
function onTimer
? "onTimer Firing"
return
function onClose
this.timer.enabled = false
*- If the timer.parent is not nulled, this form
// will not release properly.
* Comment out for demonstration only.
// this.timer.parent = null
return
endclass
class TestCForm of FORM custom
with (this)
metric = 6 // Pixels
height = 352.0
left = 371.0
top = 0.0
width = 280.0
text = ""
endwith
this.persistent = false
function Open
this.checkInstances()
return super::open()
function CheckInstances
*- Checks for previous instances of the form class in memory.
// If multiple non-persistent instances are found, then the
// form is not releasing properly.
*- Dependent on custom persistent form property that should
// only be true when you intend on leaving the form in memory
// after the form is closed.
*- Do not execute in runtime
if "runtime" $ lower(version(0))
return
endif
local oForm, nCount
oForm = findInstance(this.className)
nCount = 0
do while oForm <> null
if oForm.persistent = false
nCount ++
endif
oForm = findInstance(this.className, oForm)
enddo
if nCount > 1
MSGBOX(nCount + " Non Persistent Instances in Memory!", ;
"Warning", 48)
endif
return
endclass
|