CE memory division between “storage” & “program” memory

Somehow I’ve been involved in a bunch of discussions on this subject lately, so I figured I might as well lay out some of the issues.

Q:  What are the ways to set the way memory splits between storage & program memory?  Or in other words, how do I set the size of the object store?

A:  You have 3 options:  Set the size in OAL code by implementing the pOEMCalcFSPages function.  Set the size in OAL settings by changing the value of FSRAMPERCENT in config.bib.  Set the size at run-time by calling the SetSystemMemoryDivision function.  The CE control panel “system” applet has a slider that users can drag to adjust the size; that just calls SetSystemMemoryDivision.

Q: What is the minimum size for the object store?  If all of my device settings are stored on a persistent file system, so that I don’t use the object store at all, can I set the object store to 0?

A: There is no way to completely get rid of the object store, even in the most recent OS version (5.0).  The absolute minimum value you can use is 28KB.  If you’re using FSRAMPERCENT, use FSRAMPERCENT=0x00000004 which gives you 32KB.  If you are actually using the object store for some data, I can’t really give you a minimum.  (eg. I can’t say what the min. size required to boot successfully is.)  I suggest you find it by booting and seeing how much of the object store is consumed, using GetStoreInformation or GetDiskFreeSpace.

Q: What is the maximum size for the object store?

A: 256MB.  But since FSRAMPERCENT can’t go that high, you’ll have to use pOEMCalcFSPages for that.

Q: What is the minimum size for the program memory?  How do I guarantee that my device can boot?

A: Again, there isn’t any one minimum size I can give you.  It varies based on what components you have included in your image, and based on your own code.  What I suggest is that you find out what the minimum number of free pages was, after booting a system that has enough RAM.  Use the “mi” command from the target control window, and look for the “minfree pages” value.  That is a “low water mark” for the lowest number of free pages that were available at any one time.  Subtract that from the total pages to find out the maximum number of pages that were used at any one time.  I think the object store pages count in that total, so you should subtract the size of the object store, to get the maximum number of pages that were used for program memory.  Then add some space for safety — say 24 pages.  (I just made that number up.)  Then use that as your minimum size for program memory.  So, that means use this formula:

   (minimum RAM size) = (total pages) – (minfree pages) – (number of object store pages) + (safety margin)

Q: What is the maximum size for the program memory?

A: 512MB, minus the 28KB minimum for the object store.  There is a way to extend past 512MB but that is a story for another day.

Q: How does FSRAMPERCENT work?  It is confusing.

A: Yes, it is confusing.  To help you understand where it is coming from: back in the days when memory was much smaller, OEMs wanted ways to give stair-step functions of memory, so that they could create multiple devices that vary only by the amount of RAM inside them.  FSRAMPERCENT says, for each of the first four 2MB chunks of RAM, how many 4KB pages per 1MB should be given to the object store.  So you could say, if my device has 2MB of RAM use this much; if it has 4MB use this other amount, etc.  pOEMCalcFSPages is a later way to solve the same problem, and is much more flexible.  Anyway here are some tips for reading and setting FSRAMPERCENT:

  • To interpret a value like 0x40302010, take each byte separately.  Each byte represents the number of 4KB blocks per MB for 2MB.  So 0x40 x 4KB = 256KB per MB for 2MB; so the top byte gives 512KB of RAM to the object store, and the remaining 1.5MB to program memory.  Likewise 0x30 –> 384KB storage, 1.625MB program; 0x20 –> 256KB storage, 1.75MB program; 0x10 –> 128KB storage, 1.875MB program.  Add them together for the total: 1.25MB storage and 6.75MB program.  Check that they add to 8MB.  Beyond the first 8MB, all the memory is used as program memory (I think).  Don’t take my word for it.  🙂
  • To specify that N bytes of RAM (where 28KB <= N < 2MB) should be given to the object store, round to the nearest 8KB boundary [N], then set the bottom byte of FSRAMPERCENT to ([N] / (4096 * 2)).  So for 28K, round up to 32K, divide by 8KB to get FSRAMPERCENT=0x04.  To specify amounts between 2MB and 8MB set the bottom bytes to 0xFF, subtracting 2MB for each.
  • To specify that P% of RAM (where 0 <= P <= 100) should be given to the object store, set each byte of FSRAMPERCENT to ((P / 100) * (1MB / 4KB)), or in simplified form (P * 2.56).  So for example to use 12.5% of RAM for the object store, use (12.5 * 2.56) = 32 = 0x20.  So the 4-byte value of FSRAMPERCENT would be 0x20202020.  To use 33.3% of RAM, set FSRAMPERCENT to 0x55555555.

Q: When I change the division dynamically using SetSystemMemoryDivision or by moving the control panel slider, does that value persist?

A: If your device always warm-boots, the object store will always be there so its size will not change on reboot.  If your device always cold-boots, then the object store is recreated on every boot.  The division is NOT saved anywhere so it will not persist across cold boots.  Every time you cold boot you get whatever size is specified by FSRAMPERCENT / pOEMCalcFSPages.  (The other variant of this question is: Why doesn’t the registry value that stores the memory division seem to persist when the rest of my registry does?  The answer is that there is no such registry value.)

Q: Does all of this apply to PocketPC / MS Smartphone?

A: Well, yes, except that PocketPC (and maybe SP, I’m not sure) has a background thread that dynamically moves the memory division in the background, so that you always have some storage memory and always have some program memory.  So any changes you make on PPC/SP will quickly go away when that thread kicks in.


Comments (11)

  1. Thank you Sue for all the info in this site, it is for sure very helpful!

    Related to the answer of question "What is the minimum size for the program memory? How do I guarantee that my device can boot?"

    Could you please tell me what kind of Win32 functions to use to have the minFree pages and total pages? Is OEMInit () a good place in the OAL to return the minimum RAM size to let the OS boot safely?

    Thanks again

  2. Sue Loh says:

    From an application you can use the read-only values UserKInfo[KINX_NUMPAGES] and UserKInfo[KINX_MINPAGEFREE] to find out the total number of pages and number of free pages. Inside the OAL you’d have to refer to them differently, I think KData.aInfo[]. I don’t know what you mean about "returning" the size. Wait until you’ve gone all the way through boot — long after OEMInit() — before measuring the low-water mark.

  3. Hi Sue,

    I tried to use the KData.aInfo[] to get total number of pages & free pages inside the OAL but without sucess. I am only able to use the UserKInfo in application mode.

    IN OAL: Since I am using pOEMCalcFSPages to recalculate the size of object store, can I use the value of dwMemPages (memory reported to kernel) as (minfree pages) + (min OS RAM) + (safety margin)?

    So, that means my formula is:

    (Object store ram) = (Total ram)- dwMemPages


  4. Gordon says:

    Thank you! Its very clear and helpful.

    I found that while copy files to RAM file system and if there is no enough storage memeory, system will auto increase the size of storage memeory. But if there is no enough program memroy, no one to adjust.

    Is it right?

    Could you explain the auto adjustment?



  5. Sue Loh says:

    Zmaddi: The numbers I was suggesting were for figuring out, manually, what a good ballpark number might be. Not for figuring out programmatically during boot. For one thing, pOEMCalcFSPages is called far too early in boot for you to get a realistic approximation for how much memory is GOING to be used during boot. Reading the "minfree pages" value during pOEMCalcFSPages will almost certainly give you a bad representation of how much memory is going to be used during boot AFTER the pOEMCalcFSPages call.

    My procedures were for if you wanted to choose a hard-coded size for the object store. If you want to calculate it programmatically during boot then the best I can suggest is: pick a hard-coded minimum, then if you want it to be more dynamic based on how much ram exists on the device, pick a percentage to use beyond the minimum.

  6. Sue Loh says:

    Gordon: as I mention in the very last Q&A on the list, PocketPC is a completely different animal entirely because of the auto-adjust.

    As I understand the PocketPC auto-adjust algorithm, it tries to keep the memory division such that the amount of unused object store matches the amount of unused program memory.

    So, if there is no free storage available to convert to program memory, or if there is no free program memory available to convert to storage, then it cannot adjust to give you more.