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


Using Very large programs


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 (2)

  1. Tom says:

    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

  2. Olgunka-og says:

    <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>