Partager via


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

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