Active GUI element
Static GUI element
Code
WPS object
File/Path
Command line
Entry-field content
[Key combination]
Virtual Memory Problems under OS/2
Most OS/2 users probably have suffered from memory-related problems even if they don't know it. This article compiles related background knowledge and derives methods to at least reduce the problem.
- Introduction
- A new virtual memory model for the OS/2 kernel
- From theory to practice
- Limitations of the Virtual Address limit
- Some notes about shared memory
- Measuring and manipulating the free space in the shared arena
- Common error messages with lack of virtual memory
- Measures to optimize use of virtual memory address space
- Conclusion
- More reading
Introduction
On 32 bit OS/2 systems with 4-64 MiB physical memory I never got out of memory
errors. The
reason is that OS/2 programs use virtual memory. And OS/2 had plenty of it compared to my real memory
resources which consisted of dynamic random access memory (DRAM) chips.
The 32 bit OS/2 versions 2.0-4.0 could address the whole 4 GiB (2^32) virtual memory space of the Intel 386 processor: The first 512 MiB of the 4 GiB virtual address space were available for 16 and 32 bit OS/2 user programs and the 3.5 GiB remainder for the 32 bit kernel. So OS/2 offered each program a generous amount of virtual memory, when even only a fraction of it was physically available.
OS/2's virtual Memory Manager worked together with the MMU of the processor to keep the needed virtual memory pages in physical memory (on demand paging). OS/2 imposed several “banker's” tricks to prevent the promised memory from being committed too soon (lazy commit). Otherwise a 40 MiB hard disk would fill up easily.
Although an OS/2 programmer could write programs that used up to 480 MiB of virtual memory (the upper 32 MiB of the 512 MiB were reserved for system DLLs), no programmer would write such a program. 32 bit OS/2 programmers had worked with the 16 MiB physical memory limit of 16 bit OS/2 v. 1.x. They knew that OS/2 customers had in practice only 2-8 MiB RAM and did not possess fast and big enough hard disks to allow for the needed paging file. Memory hungry programs would be terribly slow and the system would thrash (spend all its time swapping). Unlike Unix, OS/2 and MS Windows were optimized for memory sharing between processes with minimal swapping. So programmers made use of the available PM, WPS, and other libraries, rather than re-invent the wheel.
The who-is-growing-faster? hardware-or-software? race
Today's RAM has become a cheap resource. Video cards have more memory on board than the hard disks of early OS/2 systems. Systems with 1-2 GiB RAM have become common. Users spend their money on fast static RAM caches and pipelines for the processor because even 400 MHz RAM chips are slow compared to 1500-3000 MHz processors.
Developers now write code for 32 bit operating systems with at least 2 GiB virtual memory for user programs (Windows,
Linux). High-level programming languages, growing system libraries, and even Wizards compile fat code for the latest
GUI versions of Hello world. It let Martin Reiser conclude that: Software gets slower faster than hardware gets
faster
(also known as Wirth's Law). This kind of
software became also known as bloatware.
But not only changing programming methods caused growing libraries. New libraries also opened new worlds. Take a look at the new libraries of OS/2.
Eberhard Mattes ported the Unix (EMulate UniX) C libraries to OS/2. It enabled OS/2 users to compile and run servers like XFree86, Squid, SecureShell, and Apache on OS/2. IBM's Open32 extension introduced Win32 features in OS/2 to port Lotus SmartSuite to OS/2. Win32 features like an OS/2 registry made Odin and Innotek's ports of Virtual PC, Java and OpenOffice possible. The developers of multi-platform programs like Netscape/Mozilla and StarOffice/OpenOffice.org could not depend on the peculiarities of specific GUI APIs (PM, Win32). So they introduced their own graphical libraries to facilitate porting. Thanks to their efforts we can enjoy the latest open source browsers, e-mail, and Office applications. But those gluing libraries took also their toll in terms of extra shared memory usage.
Wirth's law concerns most PC operating systems. Buying faster hardware and more RAM is the usual remedy. And as new hardware often goes with a new Windows OEM, one can see it as a Microsoft/Intel (Wintel) deal. But much more parties profited from this “who is growing faster” hardware-software race. Not the least are the computing magazines who were constantly fed with “news” and advertisements. Hardware and software resellers had to compete. And consumers could buy faster computers and slower software for less money.
OS/2 users now have plenty of RAM, but lack virtual address space
OS/2 users first profited from fast processors and cheap RAM. OS/2 2.0 was designed to let 16 and 32 bit applications work peacefully together on systems with 2-16 MiB of RAM. Using more RAM made it faster. With the introduction of Warp 4 (1996) most systems had 16-64 MiB of physical memory. But as GUIs and games demanded more memory computers with 512 MiB or more RAM have become standard.
32 bit MS Windows reserves 2 GiB of virtual memory for user programs. 32 bit Linux gives 3 GiB to them. But in OS/2 2.0 the virtual addresses had been limited to 512 MiB to let 16 and 32 bit OS/2 application share their resources and libraries. So OS/2 users cannot load programs in virtual memory as big as Windows and Linux users can. Even with 3 GiB of physical memory each program can only access the same 512 MiB of virtual memory address space. And much of that is already occupied by shared libraries.
But with the current growth of programs and libraries Linux and Windows users already get “out of memory” errors. They will move to 64 bit platforms where virtual memory resources once again seem endless. But what can OS/2 users do?
A new virtual memory model for the OS/2 kernel
Did IBM foresee these questions? Asking programmers to make use of the existing WPS and PM Application Program Interfaces (API) did not work. So IBM embraced Java.
The Java implementation of OS/2 Warp 4 used a bit 16 bit TCP/IP stack that only could serve Java programs in the first 512 MiB of virtual address space. But as these virtual addresses also had to be shared with Presentation Manager, the Workplace Shell, and other resident OS/2 applications, an OS/2 LAN Server or workstation with 1 GiB of physical memory could in practice only give some 300, maybe 400 MiB (CLI only) of memory to applications. The rest could be used as system memory via a driver, for instance as a big HPFS386 or FAT cache. But this was not enough for a server.
So in 1998 IBM changed the memory model of the Aurora kernel in OS/2 Warp Server for eBusiness (WSeB). IBM gave the OS/2 v. 4.50 kernel several options that enabled certain 32 bit user programs to use more then 512 MiB of virtual memory. Just as in [Windows] NT server and Linux the maximum virtual address limit for user programs could be set to 3 GiB with 1 GiB left for the in virtual memory residing kernel projections. So called high memory arenas (HMA) were introduced that could be accessed by Java, DB2, and a 32 bit TCP/IP stack. And the Journaled File System (JFS) allowed for a big fixed cache to load them fast.
The high memory arena feature of the Aurora kernel was also introduced in OS/2 Warp 4 with Fixpack 13. Via eComStation or the IBM Software Choice program OS/2 users got the new 32 bit TCP/IP stack. They were not automatically installed, but they became available.
The memory model of classic 32 bit OS/2
In the bar diagram the virtual memory address schemes of OS/2 2.0-4.0 and OS/2 4.5 (Aurora kernel) are compared.
Figure 1. OS/2 2.0 - 4.0 and 4.5 virtual memory address schemes
OS/2 2.0 reserved the first 512 MiB of virtual address space to user programs.
The 512 MiB addressable space was divided into an private arena for private use of code and data (yellow) and a shared arena for shared code and data (green).
In between was a pool of free virtual memory addresses that the system loader could use to allocate new virtual memory objects.
The loader placed the shared code and data of running programs preferably in its top and the private memory objects in its bottom. But in time, with the continuous loading and unloading of programs and data, the original pool of free memory would shrink, leaving a fragmented shared arena.
The rest of the Intel's 4 GiB virtual address space (3.5 GiB from hex 2000 0000) went to the shared (by all processes) part of the kernel and related drivers (the blue system arena).
The kernel itself could address 64 terabytes of virtual memory. For instance to keep track of the virtual memory usage of the other protected mode processes that were not active. But this is not visible to the protected mode programs' virtual memory world. They experience their 4 GiB world as all there is. Unless they use some special kernel APIs like Theseus.
Protected mode Dynamic Link libraries (DLLs) saw the full 512 MiB including an for shared system DLLs reserved upper region (32 MiB). In practice the free address range is much less than 480 MiB (200-300 MiB in practice) because many shared DLLs (network, PM, WPS and other APIs) are already loaded at boot time.
The memory model of the Aurora (Server) kernel
With the Aurora kernel the arrangement of the first 512 MiB of virtual memory remained the same. This guaranteed compatibility with the classic 16 and 32 bit OS/2 applications. But with the CONFIG.SYS settings:
VIRTUALADDRESSLIMIT = 2048 SET JAVA_HIGH_MEMORY=1
protected mode user programs especially compiled for the Aurora kernel had 1.5 Gigabyte virtual address space in high virtual memory arenas (private and shared) more to address. The OS/2 system running in privileged mode got the upper 2 GiB of virtual address space.
In this way Java servers and clients can be loaded high in an 32 bit OS/2 Java RunTime Environment and make use of the 32 bit TCP/IP stack with little (mis)use of precious shared resources in the first 512 MiB of virtual address space.
In Figure 1 process 1 loads part of its private and shared code high, enabling other programs to allocate more virtual memory in the first 512 MiB of virtual address space.
As you can see the high virtual arena set-up was a replication of the arrangement of the first 512 MiB, starting at address Hex 2000 0000 (512 MiB) with a private arena, followed by a pool of free virtual memory and ending in an high shared arena (in the picture below from Hex 2A50 6000 to the Virtual Address Limit).
From theory to practice
Since 1998 the OS/2 version 4.5 kernels gave room for high memory user arenas so that programs especially compiled for them could access the virtual address space up to an maximum VirtualAddressLimit (VAL) of 3072 MiB. Quite soon the default VAL changed from 2048 to 1024 MiB, as the system arena also needed room for large JFS caches and AGP buffers.
In the old 16/32 bits model one could already run, say, 50 processes using 100 MiB of protected memory (total 5 GiB). And now we can run very big processes each using up to 1-3 gigabytes of protected mode memory concurrently.
In theory the 386 processor allows for 64 terabyte of virtual memory. But I never managed to profit from it. In fact, I only can only artificially create a situation in which my 2 GiB of RAM is fully used: By using a large JFS cache and Virtual PC drivers and by (re)loading almost only private memory using Java programs like Night Vision for Java several times.
So I wondered what other factors could play a role in the common observation that OS/2 cannot use 1 or more gigabytes of external memory for normal user programs. I experimented a lot and searched the Internet. I found several limitations that only explained things partly.
Limitations of the Virtual Address limit
First of all is it unlikely that you ever will benefit from 4 GiB of physical memory. Setting a large VIRTUALADDRESSLIMIT (VAL) will easily give problems in the system arena of a desktop system.
Some problems resemble the one you get when using high memory under DOS (the 640 KiB barrier). DOS reserved the addresses above the 640 KB barrier for the PC BIOS and video memory. Only the high memory addresses that were not used or could not be remapped to extended memory addresses above 1 MiB (for instance using QEMM) were available.
32 bit PC systems have similar hardware related problems.
-
Though the Intel 386 processor can externally address 4 GiB of physical memory, most motherboards support only 3.5 GiB of RAM as the upper 3.5-4 GiB address range go to PCI bus and APIC mappings.
-
Modern videocards with 256 MiB of video memory place large framebuffers in the protected mode part of the system arena. (This may be a reason that raising the VAL from 2048 MiB to 3072 MiB prevented my OS/2 GUI from starting when using 2 GiB of RAM.)
Some system limitations may have to do with the need of sharing system resources. Although the OS/2 kernel may address the full 64 terabyte of the 386 virtual memory, much of it also seems to be made available in the 4 GiB minus the VAL system arena of protected mode programs.
-
The higher the Virtual Address Limit (VAL), the more system resources OS/2 must reserve per process. Page and other system tables must contain more and longer addresses. This could be an explanation of the fact that with higher VALs less threads can be reserved and less processes can run concurrently. Especially if you do not lazy commit.
-
With
IFS=C:\OS2\JFS.IFS /CACHE:512000
(about 512 MiB) and a VAL of 2048 MiB most of the resident memory of the system arena goes to the JFS cache as Theseus > Kernel Information > Kernel Memory Usage shows:Memory Usage for System Memory (memory in the 'System' Arena): allocated committed present resident Totals -------- -------- -------- -------- 7292B000 2467A000 2465B000 238EC000 Total (in bytes) 1877164 596456 596332 582576 Total (in Kbytes) 1833.168 582.477 582.355 568.922 Total (in Mbytes)
Lowering the JF cache to 256000 freed some 280 MiB of memory (needed for the cache proper and the cache tables). But when I used a VAL of 2560 MiB with
/CACHE:512000
the GUI started, but the JFS cache defaulted to 64 MiB according to cachejfs. Though I had enough RAM, the system memory needed above the VAL could not be allocated. -
Innotek's Virtual PC loads its Virtual Machines high, but it does so by means of a device driver. So the virtual machines are loaded high as system memory. But if you want to load, say, three 512 MiB using VPC guests in the system arena, you must reserve 1.5 GiB VPC + the JFS cache and its cache tables + AGP buffers + shared kernel and driver space in the system arena of every 4 GiB protected mode process. If you want a 512 MiB JFS cache, I would advise you a 1532, or better 1024, VAL with 512 or less threads. With a VAL of 2048 the system could become unstable.
Programs using high memory
The introduction of high memory arenas up to an virtual address limit of 3 GiB was a major improvement.
Figure 2. Virtual PC and Flash DLLs loaded high
But to use the high memory addresses, programs have to be (re)compiled for it. Programmers need to use
DosAllocMem()
with a special OBJ_ANY flag:
#define OBJ_ANY 0x00000400 /* allocate memory anywhere */
Or the linker option -Zhigh-mem in GCC to let OS/2 load their code and data high.
Such programs do exist but they are still rather uncommon.
Moreover they must still cooperate in low memory with programs that are not compiled for the high memory code. Unlike Unix, OS/2 was developed for sharing. So a Java RTM or DOS prompt are connected to SOM.DLL and WPS extensions even if they cannot do anything with it.
And the programs compiled especially for high memory usage still allocate low virtual memory when the OS/2 loader offers it to them… Programs that can load their code and data in high memory arenas do not automatically use the available high memory.
The 32 bit Windows programs loaded via Odin technology are not concerned with OS/2's memory model. They generally run where they are loaded. And if there is a pool of free memory in the lower user arena, they occupy it preventing classic 16 and 32 bit OS/2 programs tfrom using of it. The Windows compilers do not know that classic OS/2 programs (with a VAL of 512 MiB) are different from 32 bits Windows applications (using a VAL of 2048).
So to run as many applications as possible, it may be necessary to load classic CLI, PM, and WPS programs first to let them fill the lower memory regions, which forces the OS/2 loader to load the WIN32 code and data high.
When “forced,” VPC (vpcwgss.dll, vpcwin.dll) and Flash libraries (flashwin.dll) can be loaded in high shared memory as Theseus shows. But this is unlikely to occur when VPC is the first program that you start up.
Innotek's Freetype Font Server is automatically loaded high. Placing FT2LIB in the lower shared arena would reduce the address space of all OS/2 applications as they all had to share the 32 MiB object.
In the Theseus example above there is 30.125 MiB free address space between the private and shared arena, but no
free memory pools, which indicates external fragmentation. The 32 MiB object FT2LIB could not be
loaded at all in the first 512 MiB of virtual address space. Because of this virtual address space
fragmentation, closing programs to free shared memory seldom frees enough continuous free address space
to load a 30 MiB memory object like a font cache or a CDRecord buffer. So a DosAllocSharedMem()
would fail. You would
have to reboot and let OS/2 load them again in an uncluttered shared arena.
Other programs I saw using the high memory arenas were PMView, WarpVision, Lucide, EmperoarTV, Opera, Innotek's OpenOffice.org, Win32 Java, and the Mozilla family (“HiChunk”). They all used private memory at Hex 2000 0000 and above.
But even though the Mozilla builds and OpenOffice.org can use high memory, they still use much memory in the shared arena as well. This is the main reason that PM and the WPS on my 2 GiB OS/2 system regularly get stuck. Or OpenOffice.org fails to load. Not because of lack of memory, but because of lack of usable virtual address space.
Some notes about shared memory
The shared arena was meant for sharing
When several programs need a similar functionality (say PM Window functionality), the functions can be implemented in a specialized Dynamic Link Library (DLL). When called, the system loader loads the specialized files (dll, drv, fon) in the shared virtual memory arena so that their code, resources or data can also be accessed by other programs (shared storage).
Effective reuse of code saves time and memory: When Presentation Manager (PM) programs need to draw their windows, they make use of already loaded dynamic link libraries of the OS/2 Presentation Manager API. And when the PM program Mozilla loads Times.fon, other applications do not need to load the resource again. Another advantage of DLLs is that they can be easily replaced on an individual basis without messing around in the whole system or program.
Not all shared memory is effectively shared
But not all parts of the shared arena are reused. Of course all instances of process 1 can reuse the contributions of the first instance of process 1 to the shared arena and probably the shared code and data of PM Shell and the OS/2 system services. So loading a second version of a program often consumes less memory than the first one. But the shared memory owned by process 2 might be forbidden for process 1, or just be too incompatible, exotic or undocumented to be of any practical use.
In the worst case a process “donating” or leaking hundreds of megabytes of useless code or data in the shared arena could consume all free virtual memory preventing other programs from loading or functioning. The WPS would hang and only memory resident system utilities like CAD handler or Watchcat could kill the offender.
I don't know how OS/2 Warp 4 handles a program that uses 400 MiB of low private memory. But it certainly could not co-exist with a 200 MiB shared arena, so the process would trap or it would trap the WPS. But I have seen situations in which Mozilla private memory usage in RAM already grew to 200 MiB and more (keep on browsing) which resulted in the not so well known Common error messages with lack of virtual memory and a non responding WPS.
Investigating library dependencies.
The virtual memory size of an user process consists of its private arena and that part of the shared arena that it (re)uses. But because Dynamic Link libraries are often dependent on DLLs from other parties (see DLL tree below), program boundaries in a GUI are not clear. WPS programs (enhancers, additions) even run and communicate within one big process (the second PMShell.exe).
This blurriness of boundaries plays a role in the so called DLL hell. OS/2 users see this with incompatible Mozilla builds. Different programs (exe or DLL) using incompatible shared libraries (builds, versions) with the same name.
You can investigate the dependencies of DLLs with EWS utility DLL Tree (pmdll28.zip). When you make an WPS object of the program, give PMDLL.EXE the current directory (.) of the LIBPATH as its Working Directory. You can associate it now with *.EXE and *.DLL files. Right clicking on it and opening an OS/2 EXE program or DLL file with PMDLL will show you its DLL dependencies.
Figure 3. DLL hell? [Larger image]
In the above case an incompatible library (MOZJS.DLL from SeaMonkey) is already loaded in shared virtual memory under its name (MOZJS), preventing Thunderbird to dynamically load its version of MOZJS.DLL (red = not loadable). As FC/2 shows they are different in size. But Rick Walsh's Run! utility could load Thunderbird [by renaming a copy of run!.exe to thunderbird!L.exe] for me. In this case both versions of MOZJS seem to have gone.
To circumvent incompatibilities of dynamic link libraries program libraries can be compiled static. Then the needed code from libraries is included in the EXE-file and so do not need to be dynamically reloaded. But this approach makes big exe-files using a lot of private memory. The approach does not fit with the Windows and OS/2 strategy to (re)use as much shared libraries as possible. But if you really need to run a program that might not fit with the rest of your system libraries, static compilation of needed libraries is the way to go.
With recent OS/2 4.5 kernels manipulating the LIBPATH with the local environment variables BEGINLIBPATH
and LIBPATHSTRICT=T
in a CMD file or with the Run! utility is an alternative. This is an OS/2 variant of the standard
Windows NT loader method (see kdb
100635) of reloading an DLL found in BEGINLIBPATH into different virtual and physical memory pages if it is
incompatible with an already loaded DLL. Windows NT always loads 32 bits shared Windows DLLs in a different virtual
location, but maps them to the same physical memory if they seem the same (viruses and root kits do this). Under
OS/2 this can only occur if your batch used LIBPATHSTRICT=T
.
For setup details see Steve Wendt's Warpzilla -
Mozilla for OS/2. The OS/2 default is SET LIBPATHSTRICT=F
, meaning that the already loaded DLL or the DLL found first in
the LIBPATH is used.
Classic 16 and 32 bits OS/2 programs must share the same 512 MiB of virtual address space
Figure 4. Failure to load OO.org
Lack of physical memory is not problem as long as the most used code and data (the working set) of your programs can be kept in memory. And as OS/2 is specialized in low memory conditions this is often the case. When the working set of an threaded OS/2 program fits into a static RAM cache, OS/2 runs it super fast.
But lack of usable virtual address space can limit the loading of new programs when you have plenty of RAM.
Though it should be theoretically possible to run thirty 100 MiB OS/2 processes in private virtual memory and so benefit from 3 GiB of RAM even with a virtual address limit of 512 MiB, I have found that in practice (2 GiB system) the sum of memory loaded by all user processes (mapped part of 1,2 and 3) and their contributions to the shared arena (green) should be less then 500 MiB or “out of memory” errors occur. Using applications that could partly load in high memory, I could at most get some 600-700 MiB of user processes in RAM using the WPS.
One factor could be that the modern big programs that can load their memory high do not do so. At least not in a way that leaves sufficient room for more classic lean and mean OS/2 programs. Another factor is the free arena fragmentation of which the larger low memory using processes may suffer most.
Measuring and manipulating the free space in the shared arena
Jan van Wijk made two CLI utilities that are useful in investigating the free address space in the lower shared arena.
The SHMEMMON (shmemmon.zip) utility monitors free memory in the shared arena. SHMEMMON 1 gives the free space in the shared arena, updated once a minute.
Monday 18-09-2006 23:15:24 - Available: 891 256Kb blocks = 222.7 Mb Monday 18-09-2006 23:16:25 - Available: 20 256Kb blocks = 5.0 Mb
Here the free space in the shared arena dropped suddenly from 227.7 MiB to 5.0 MiB because 200 MiB of virtual memory was committed to the the other utility SHMEN (shmem.zip) with the parameter 200.
SHMEM.EXE 1.4 Display/Eat shared memory. (c) 2002 Fsys Software; Jan van Wijk Monday 18-09-2006 23:16:04 - 200 1 Mb blocks = 200.0 Mb allocated. Press any key to free it again ...
The “Press any key to free it again ...” is important because with only 5 MiB of free shared virtual address space left all kinds of errors may occur if you keep on working simply because most classic OS/2, DOS, and 16 bit Win/OS2 programs have to allocate some shared virtual memory to let you do your things. In fact I soon had to reboot…
But poisons can be medicines too. A potential beneficial use of SHMEN could be to temporarily reserve a pool of low shared memory for later use (shmem 100 -s -h). When the lower shared arena becomes smaller, the OS/2 4.5 system loader is more inclined to load Innotek's Odin-ized WIN32 and applications like Mozilla in high memory. The “Press any key” could be used to release the reserved address space and then, after loading your applications, SHMEN could be restarted again as shmem 50 -s -h. A REXX script could do it. But to my surprise many applications were unable to use the freed virtual memory.
So just having enough free memory in the shared arena (the shared memory monitor output) is no guarantee that programs will load. Even when there is, say, 200 MiB of free shared memory, loading problems can still occur when the system loader is confronted with internal fragmentation in the lower shared arena. In this case the system loader may be unable to load the larger “memory objects” of big DLLs or find holes for the needed DLL trees of smaller DLLs in its already restricted shared user arena.
You can check for fragmentation in the shared arena with the Theseus function Linear Usage by Process. Scan with [Ctrl-F(ind)] and [Ctrl-A(gain)] for the word “Free” and watch the sizes of the free memory objects. The upper and lower borders of the shared arena can quickly be found by searching for the word “arena”.
There is 0.000M between the private and shared arenas. Shared arena starts at 08D50000, which is 141.313M. Free memory from 08D50000 for 65.938M, which is equivalent to 1055 64K spaces. 0CF40000 ........w...ww...ww.wwwwww.wwwwwww.wwww....wwwwww.ww 22 PMMERGE allocated it object is 128K Free memory from 0CF60000 for 768K, which is equivalent to 12 64K spaces.
In this case the biggest free memory object in the shared arena (starting at 141.313 MiB, about the size of the biggest process in the private arena) was 65.938 MiB. The second free object at linear address 0CF60000 was 768 KB. More small free objects followed. The total free space in the shared arena was 123.375 MiB. About half of it was fragmented.
Total number of committed pages = 21578. Total free space in the shared arena = 123.375M. Above 512m Private arena starts at 20000000, which is 512.000M.
Common error messages with lack of virtual memory
If the address space for programs in the first 512 MiB of virtual memory is mostly consumed, programs can display all kinds of error messages and behave in unpredictable ways. Have a look at Figure 5 to see what I mean.
Figure 5. Program load failure due to insufficient address space [Larger image]
On a 512 MiB RAM eCS system there is 206.5 MiB of physical memory free, but Lotus Organizer fails to load. The (LIB)PATH is correct. The WPS settings are correct. The program worked flawlessly before. So the suggestion of the pop-up window that there might not be enough memory available could be correct.
The pop-up window suggests lack of memory, but what it really means is a lack of virtual memory because protected mode OS/2 programs use virtual memory. Lack of virtual memory in the shared arena would also explain that the big ORG32B.DLL (925.370 kB) cannot be loaded as the PM program DLL Tree (pmdll28.zip) reports. Lack of RAM (206 MiB free) cannot be the problem, but lack of usable address space in the low (< 512 MiB) virtual memory arena prevented ORG32B.DLL from loading.
After closing some applications, a WPS reset or just restarting members of the Mozilla family—all measures to free virtual memory—Organizer would probably start up again.
The essence is that an user program can only use virtual memory. It cannot access physical RAM, which is protected by the operating system. But if there is not enough usable virtual address space left in the free and shared arena in the first 512 MiB, many OS/2 programs cannot load new code and data. Only programs that can (re)use already loaded libraries, load their libraries and data high or need relatively small “memory objects” that can use a small hole in the shared arena, do have a chance to start up. But many will malfunction.
-
A program may complain about lack of memory: “SYS0008: There is not enough memory available to process this command. All available memory is in use.” But you must realize that lack of virtual memory is what is meant. Tweaking the buffers and HPFS cache really makes no sense on 128 MiB RAM systems. Here you should use the maximum settings.
-
Very often a program will give an error message that it “cannot find” (read: load) a needed Dynamic Link library (DLL) or helper program. If the helper program or library is not in the (LIB)PATH or the working directory (the . of the LIBPATH), this is a normal and justified error message, but when it is in the (LIB)PATH the inability to load a new DLL is a symptom of lack of usable virtual memory space.\ This is especially true if the program behaves normally again after virtual memory eaters like Mozilla or OpenOffice have been closed.
-
Sometimes a program just won't start. A caveat can be the DLL hell known from early Windows versions. Different builds of the Mozilla family will use incompatible shared libraries. This may happen if you first start up Firefox, then an incompatible Thunderbird build that does not start up, or vice versa. See my notes on shared memory. In fact this is a “not expected kind of virtual memory” situation. But it resembles the situation in which they are out of (virtual) memory that is not expected by OS/2 programmers or their compilers. But the way they behave can look the same.
-
When a program does not start and leaves no error message in a pop up window, start it via command line. You may then now see an error code like this:
Unable to start 'FIREFOX.EXE' - rc= 8 - possible cause: 'I:\OS2BIN\INTERNET\FIREFOX\NSS3.DLL'
In this case the rather large NSS3.DLL (467.657 kB) was not loaded because of lack of virtual memory space. Other Mozilla applications were then not running but the VM address limit was set to 512 MiB...
-
A running program may lose functionality. For example, Post Road Mailer does not filter its mail, PM buttons are not drawn, or pop-ups windows and help files have no messages.
-
You may find SYS2070 errors (“SYS2070: A program in this session encountered a problem and cannot continue”) in popuplog.os2 and hear system beeps.
-
Unix servers can complain about “cannot fork” because more virtual memory is needed for loading a new child process.
-
The WPS gradually uses more virtual memory as it loads more DLLs and data. DLLs that are not used any more are not unloaded as long the WPS is not reset. DLLs and data of unneeded WPS features (enhancers) are swapped out of physical memory, but they are kept in virtual memory as long as the second PM Shell process exists. That is the reason why the swapper.dat keeps growing on systems with 4-32 MiB of RAM. The DLLs are unloaded only when the WPS process is reborn. So resetting the WPS is a good strategy to free virtual memory.
-
In the worst case PM Shell gets into trouble. This is the case when PM cannot (re)draw its PM windows and WPS folders show no icons, but it becomes a major problem when programs do not react to the Task Manager ([Ctrl-Esc]). This might be PM's single message queue problem, but when even Watchcat cannot terminate programs (prg exit T1 with no result) lack of usable memory resources is more likely.
Figure 6. Screen update failure due to lack of free low virtual memory [Larger image]
In the PMView Pro screen shot above there was more then 1260 MiB of physical memory free (2 GiB RAM eCS system with 512 MiB JFS cache), but Theseus told me that “There was 0.000M between the private and shared arenas.” The WPS and PM were not available so I had to run Theseus via Watchcat's shell: getlinmp.cmd > %TEMP%\theseus.txt. I could free low virtual memory via Watchcat. But the Win32 programs (Innotek's OpenOffice and Acrobat Reader) did not respond to Watchcat's calls (prg exit T1 without result). The PM Window of OpenOffice stayed black. So I had to reboot and start again.
By the way: This picture could not be taken without PMView Pro. It was one of the first shareware applications to effectively use high memory. PMView worked in situations where PM and the WPS failed.
Measures to optimize use of virtual memory address space
How can you prevent out of memory situations? How can you make use of the hundreds MiBs of free RAM on 1 GiB or more systems?
The first thing is to be aware of the existence of low virtual memory situations. They happen suddenly on systems with plenty of physical memory (128 MiB or more) and enough room for the swapper.dat. When you load too many programs on a system with too little RAM, OS/2 gradually slows down because of disk swapping. But out of virtual memory problems come out of the blue. Even when the bucket is full, the already described symptoms keep on coming.
When programs cannot find their promised (virtual) memory resources, they stop functioning properly. But their cannot find DLL or out of memory error messages can be misleading if one is not aware of the fact that user programs use virtual memory; not the physical RAM that is owned by the kernel.
Identify and tame the high memory using programs
-
Programs using a lot of virtual memory can easily be identified using Theseus. Theseus can also help you to identify less virtual memory (and processor time) consuming programs and configurations that do the same for you.
-
Closing one big spender (> 100 MiB) frees virtual address space for many smaller user programs (<10 MiB).
-
Programs reusing shared libraries via the LIBPATH should use less virtual and real memory then programs that load their "private" DLLs via BEGINLIBPATH and
LIBPATHSTRICT=T
or the Run! utility. But I could not confirm this with Theseus (Select Mozilla in Theseus > Process > Memory Utilization). -
Some programs only run if they can load large memory objects in free continuous memory space, which means that they should be loaded before the virtual address space in the shared arena becomes to fragmented.
-
Closing and reloading programs gives the OS/2 loader a change to rearrange virtual memory. Regularly closing and reloading the programs of the Mozilla family saves a lot of real memory too. But at a certain moment you may have enough shared memory, but cannot start the bigger programs because of fragmentation in the shared arena. Then you should reboot.
-
Resetting the WPS periodically is good method to free virtual memory. The WPS caching of DLLs and objects in virtual memory might have been useful on < 64 MiB systems, but leads to instability when the shared arena fills up. The objects can now be reloaded from the much faster hard disks.
-
WPS additions that you do not need, should be deregistered. In case of doubt, you can use Theseus > System > Linear Usage by Process to see how much virtual memory the registered DLL consumes.
Offer programs high virtual memory arenas
-
Always offer programs high virtual memory arenas. You need a version 4.50 kernel. Check it on the prompt with: VER /F. Then you can put a
VIRTUALADDRESSLIMIT=1280
(range 512-3072) in the CONFIG.SYS. -
Avoid
VIRTUALADDRESSLIMIT
values of 2048-3072 when system (JFS, VPC, SVISTA) and device drivers (AGP) need a large system arena, if you want to run many small programs, or you have a highTHREADS
setting. The GUI might not start up. On desktop systems values between 1024 and 1536 work fine. -
To load Java programs high with IBM's Java put
SET JAVA_HIGH_MEMORY=1
in the CONFIG.SYS. To use the highly (>512 MiB) loaded Java code on the Internet, the 32 bit TCP/IP stack 4.1 and later is needed. -
Innotek's OS/2 enabled Win32 version of Java can use the high private memory arena as do other Odin based applications. But Odin applications can also use excessive amounts of virtual memory in the lower arenas.
-
Load the needed classic OS/2 programs in their first 512 MiB, before Odin-ized Win32 programs and Mozilla browsers occupy most of the low regions. Only the last can be forced to load partly high.
Make more use of system memory
-
Make more use of system memory when you always have a lot of physical memory free. When you always have 200 MiB of RAM free, why not give it to the JFS cache or another system driver?
-
If you still have hundreds of megabytes free, you can put the swapper.dat on a JSF drive and change the CONFIG.SYS statement
MEMMAN=SWAP,PROTECT
toMEMMAN=SWAP,PROTECT,COMMIT
. Memory usage and the swapper.dat in (SWAPPATH=
) grows fast, but you are warned sooner when virtual memory resources are low. On current systems with fast hard disks and much RAM the 100 of times slower systems designed "lazy commit" method is not needed.
-
If you have 2 GiB or more RAM, the CONFIG.SYS statement
MEMMAN=NOSWAP,PROTECT
is probably the easiest way to let OS/2 fully use your memory. OS/2 becomes very fast, but you can easily run out of memory.
Other useful tweaks
Figure 7. Optimum settings
-
If you don't need to run DOS or Win-OS/2 applications you can use
PROTECTONLY=YES
and REM(ove) the CONFIG.SYS driver entries with (M)DOS in it. -
The CONFIG.SYS statement
THREADS=512
reserves less virtual memory resources thenTHREADS=1024
. So if you don't need the higher value and encounter problems when loading new programs, you should certainly lower it. For me,THREADS=400
(laptop with < 512 MiB) or 600 (2 GiB Desktop) works fine. -
The CONFIG.SYS setting
PROCESSES=256
is normally not set. It denotes the maximum number of processes one can load. You can find the default value in Theseus > System > General System information under QSV_MAXPROCESSES. It defaulted to 801 on my 2 GiB RAM system, which is very high. When I reduced it to 256, OS/2 (PM, WPS) became more stable. -
The CONFIG.SYS statement
DLLBASING=OFF
frees some virtual memory in the user arena by loading system DLLs compacted (Oct 2002). -
Many other CONFIG.SYS settings use system memory. So there is seldom need to lower the size of hard disk caches, buffers, etc., on systems with plenty of RAM.
Conclusion
When I started my investigations with Theseus, I was disappointed that I could not fully use 2 GiB of main memory under OS/2. I found out that giving OS/2 programs a corset let me load more applications.