Specifying the size of the program cache
A customer asked
1) Is it better to set it to 0 (Auto) or some "larger" number, such as -16 (1024kb). I haven't found any information in the help files as to where the tradeoff lies between these, but presumably the default for MTDLLs of 128kb is deliberately small to prevent each thread requiring too much RAM.
2) The second thing is that when I query the current PROGCACHE setting (using SYS(3065) for the DLL without any CONFIG.FPW, it sometimes returns -2 (the stated default) and sometimes 0. I suspect this could be why the problem seems to be intermittent, with a page refresh often causing the second request to work. Could this be a VFP bug or something to do with the configuration of the webserver and how it is calling the COM object?
The ProgCache setting is used to set how much memory VFP will set aside for the program cache. When you execute some code, it gets loaded and stored into this cache. When a program gets loaded, the binary compiled file gets loaded and fixups are applied. Such fixups are things like names in the compiled code are mapped to names in the current name table. For VFP versions prior to 9, the cache was set to about10 megs, and the user could not change it. For multiple threads, each thread would create its own cache, which means 20 threads would use 200 megs of memory. Actually, the memory isn’t really used until necessary: it’s VirtualAlloc’ed with the MEM_RESERVE parameter, which reserves 200 megs of virtual address space out of the available 2^32 = 4 gigs.
For VFP9, I added the PROGCACHE setting that user’s can set in config.fpw. Setting it to 0 means that no cache will be used: programs will be loaded into dynamically allocated memory, rather than a prereserved cache.
To query the ProgCache setting, use SYS(3065)
Keep in mind that “without any CONFIG.FPW” should be confirmed via querying both internal and external CONFIG.FPW files (sys(2019))
Try running the code below, varying the progcache setting and the size of the generated program (n) to see the effects. It generates a VFP COM server with a particular ProgCache setting, and then tries to run a very large program. Try causing a failure with various ProgCache settings.
See also: Collecting garbage at the wrong time
For more about the program cache, see Windows Security and how it affects running generated code
For more about memory usage, see Inspect your memory image and see fragmentation
CLEAR ALL
CLEAR
#define cProgName "testPCCache"
Cleanup()
TEXT TO cStr NOSHOW textmerge
EXTERNAL FILE config.fpw && comment this line in/out
DEFINE CLASS c1 as session olepublic
func MyEval(cExpr as string, p2 as Variant, p3 as Variant, p4 as Variant, p5 as Variant) as variant helpstring "this is the Eval help"
RETURN &cExpr
func MyDoCmd(cCmd as stRing, p2 as Variant, p3 as Variant, p4 as Variant, p5 as Variant) helpstring "this is the docmd help"
&cCmd
ENDDEFINE
ENDTEXT
STRTOFILE(cStr,cProgName+".prg")
TEXT TO cStr NOSHOW textmerge
*progcache=0 && uncomment this line to see the results
ENDTEXT
STRTOFILE(cStr,"config.fpw")
BUILD PROJECT (cProgName) FROM (cProgName)
BUILD MTDLL (cProgName) FROM (cProgName)
ox=CREATEOBJECT(cProgName+".c1")
?ox.MyEval("_vfp.ServerName")
?"Cfg=",ox.MyEval("sys(2019,2)")
?"Sys(3065,0)",ox.MyEval("sys(3065,0)")
?"Sys(3065,1)",ox.MyEval("sys(3065,1)")
n=578 && 578 passes, 579 fails w/ -2
SET TEXTMERGE TO tt2.prg on noshow
\y='a' && this is used in a CASE statement *way* down there
\Do Case
\Case Y = 'a'
FOR i = 1 TO n
\ x="<<REPLICATE("a",100)>>"
ENDFOR
\ y="b"
\Case .T.
FOR i = 1 TO n
\ x="<<REPLICATE("a",100)>>"
ENDFOR
\ y = "a"
\ENDCASE
\set compatible on
\IF y="b" then
\ cret= "DOCASE:PASS "+TRANSFORM(FSIZE("tt2.prg"))
\ELSE
\ cret= "DOCASE:FAIL "+TRANSFORM(FSIZE("tt2.prg"))
\endif
\set compatible off
\return cret
SET TEXTMERGE to
COMPILE tt2
try
?ox.myeval("tt2()")
CATCH TO oex
?oex.message
ENDTRY
ox=0
Cleanup()
PROCEDURE Cleanup
IF FILE(cProgName+".dll") && cleanup
DECLARE integer DllUnregisterServer IN (cProgName)
DllUnregisterServer()
CLEAR DLLS
ENDIF
RETURN
Comments
- Anonymous
June 19, 2006
Hi Calvin,
Thanks a lot for explaining this further. I'm now confident that a CONFIG.FPW with PROGCACHE=0 is going to stop this issue from occurring.
The system didn't previously have a CONFIG.FPW. Sys(2019,2) returns "". It shouldn't have an external file as it's a DLL and sys(2019,1) returns "" anyway.
sys(3065,0) alternates between 0 and -2, seemingly every page refresh but it could be time related.
I couldn't get this to happen using the above program: I tried building the DLL, and calling a TT2() repeatedly then cleaning up but I couldn't get it to unload tt2.fxp using ox.DoMyCmd("release procedure tt2") or ox.DoMyCmd("set procedure to")... Using a different PRG/FXP name for each iteration worked but didn't expose the problem.
Tom - Anonymous
October 06, 2008
<a href= http://index1.assqer.com >orange barrel media</a> <a href= http://index2.assqer.com >emma nelson</a> <a href= http://index3.assqer.com >weather underground weaverville north carolina</a> <a href= http://index4.assqer.com >leather hides</a> <a href= http://index5.assqer.com >why does my dvd now say wrong disc or no disc in dvd player</a>