home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-06-01 | 4.6 KB | 116 lines | [TEXT/R*ch] |
- /*
- VirtualTemporaryMemory
- ©1996 Stuart Cheshire <cheshire@CS.Stanford.EDU>
-
- Sometimes a program can run in a small amount of memory, but can run a lot
- faster if it has more memory available. Recently I wrote a program like this
- called StUU (ftp://bolo.stanford.edu/Public/Stuart%27s%20tech%20notes/StUU/).
-
- StUU is a super-fast UUdecoder. If there is only 1K of free memory, then StUU
- can still decode the file correctly by reading 1K at a time from the disk,
- but if there is 1MB or 10MB available, or more, then it can decode much
- faster by reading larger blocks from the disk.
-
- In StUU 1.0 I decided how much memory to use in the obvious way, by calling
- TempMaxMem to see how much free temporary memory was available. This worked
- fine on my Mac, but on Macs with RAM Doubler or Virtual Memory turned on it
- locks up the Mac. The Mac is not crashed -- it is just thrashing the virtual
- memory system so badly that it will take hours to finish decoding. One of
- those cases where more is less.
-
- So, how does a well written program decide how much memory to use?
-
- After pondering this problem for a while, here is the solution I have come
- up with:
-
- If VM (and RAM Doubler) is off, then just use the normal TempMaxMem call,
- else:
- 1. See how much "holdable" RAM is available. Holdable RAM is the subset of
- Physical RAM that is available for applications to use.
- 2. Tentatively decide to use the amount of holdable RAM that is free (not
- currently in use by any other program), or if the amount of free holdable
- RAM is less than 1/16 of the total holdable RAM, tentatively decide to use
- 1/16 of the total holdable RAM (it's okay to steal a little back from other
- applications).
- 3. If the amount that TempMaxMem told us to use is more than the amount
- we have decided is safe (which is usually the case), we stick to our own
- estimate and ignore TempMaxMem. If TempMaxMem tells us less is available
- (which could happen if the Mac was *really* loaded and there really just
- isn't any memory left) then we use the amount it says.
-
- To summarise, the formula for the amount of memory to use is:
-
- my_estimate = max(free holdable RAM, total holdable RAM / 16)
- amount_to_use = min(TempMaxMem, my_estimate)
-
- If you have an existing program that currently calls "TempMaxMem", just
- paste these routines into it and call "sensibleTempMaxMem" instead.
-
- NOTE: If your program decides to use all available RAM in this way, it MUST
- do it only for a few seconds at most. If you hold the memory for a long time,
- the user is going to be VERY annoyed when they find that their 64MB Mac
- doesn't have enough free memory left even to launch TeachText. StUU, for
- example, typically launches, finishes decoding, and quits in under ten seconds.
- This, I think, is acceptable.
- */
-
- #ifdef __MC68K__
-
- // The definition of GetHoldableBytes for 68K code
-
- #if !GENERATINGCFM
- #pragma parameter __D0 GetHoldableBytes()
- #endif
- extern pascal Size GetHoldableBytes(void) TWOWORDINLINE(0x70FD, 0xA05C);
- #else
-
- // The definition of GetHoldableBytes for PPC code
-
- static pascal Size GetHoldableBytes(void)
- {
- static short GetHoldableBytes68K[] =
- {
- 0x70FD, // moveq #-3,d0
- 0xA05C, // MemoryDispatch
- 0x4E75, // rts
- };
- enum
- {
- uppGetHoldableBytesProcInfo = kRegisterBased
- | RESULT_SIZE(kFourByteCode) | REGISTER_RESULT_LOCATION(kRegisterD0)
- };
- return(CallUniversalProc((UniversalProcPtr)GetHoldableBytes68K, uppGetHoldableBytesProcInfo));
- }
-
- #endif
-
- static Size sensibleTempMaxMem(Size *grow)
- {
- Size freemem = TempMaxMem(grow);
- long VMAttr, PhysicalRAM, LogicalRAM;
-
- // if VM on, see if we can revise our estimate of free memory to a more sensible value
- if (TrapAvailable(_Gestalt) &&
- Gestalt(gestaltVMAttr, &VMAttr) == noErr && (VMAttr & (1 << gestaltVMPresent)) &&
- Gestalt(gestaltPhysicalRAMSize, &PhysicalRAM) == noErr &&
- Gestalt(gestaltLogicalRAMSize, &LogicalRAM) == noErr)
- {
- // See how much physical RAM is available
- // If MemoryDispatch is available, use it, else just use
- // a simplistic estimate that half of the physical RAM is holdable
- Size holdable = TrapAvailable(_MemoryDispatch) ? GetHoldableBytes() : PhysicalRAM / 2;
- // See how much memory is in use
- Size usedmem = LogicalRAM - TempFreeMem();
- // See how much physical RAM is free
- Size useable = 0;
- if (holdable > usedmem) useable = holdable - usedmem;
- // If there is very little (or no) physical RAM left, then we'll
- // steal 1/16 of the holdable pages (e.g. 1M on a 16M machine)
- if (useable < holdable/16) useable = holdable/16;
- // If our initial freemem value is more than this amount
- // that we deem sensible to allocate, reduce it
- if (freemem > useable) freemem = useable;
- }
- return(freemem);
- }
-