Win16 Memory Management

supermatou1 pts0 comments

Win16 Memory Management | OS/2 Museum

Skip to content

OS/2 Museum

OS/2, vintage PC computing, and random musings

Home<br>About

Wanted List

OS/2 History

OS/2 Beginnings

OS/2 1.0

OS/2 1.1

OS/2 1.2 and 1.3

OS/2 16-bit Server

OS/2 2.0

OS/2 2.1 and 2.11

OS/2 Warp

OS/2 Warp, PowerPC Edition

OS/2 Warp 4

OS/2 Timeline

OS/2 Library

OS/2 1.x SDK

OS/2 1.x Programming

OS/2 2.0 Technical Library

OS/2 Videos, 1987

DOS History

DOS Beginnings

DOS 1.0 and 1.1

DOS 2.0 and 2.1

DOS 3.0, 3.1, and 3.2

DOS 3.3

DOS 4.0

DOS Library

NetWare History

NetWare Timeline

NetWare Library

Windows History

Windows Library

PC UNIX History

Solaris 2.1 for x86

&larr; Learn Something Old Every Day, Part XXI: VGA Memory Access Is Complicated

Win16 Memory Management

Posted on June 5, 2026 by Michal Necasek

This is a kind of knowledge base article which resulted from attempts to understand exactly how memory management works in 16-bit Windows. It is not exactly undocumented, but it is also not well documented; even before Windows 3.0 appeared, the assumption was that essentially all application developers were going to use a high-level language and their development tools would take care of the low-level details.

Furthermore, nearly all materials for beginning Windows developers focused on the more visible aspects of Windows programming, i.e. windows, icons, menus, and so on. Memory management was glossed over, even though it was absolutely critical to writing a solid Windows application any more complex than a Hello World program.

Windows 3.0 SDK HeapWalker memory analysis tool

The memory management details and mechanisms are rooted in the 8086 real mode history of Windows 1.x and 2.x, and much of the complexity persisted even when Windows only ran in protected mode starting with Windows 3.1.

Unless noted otherwise, in this article "Windows" refers to the 16-bit line of Microsoft products, not Windows NT.

Introduction to Windows Memory Management

The key to understanding Windows memory management is that from the very beginning, Windows was among other things a fancy overlay manager. For many years, Windows was too big for typical PCs of the time and needed some way to keep only the most active memory segments in physical RAM, with some mechanism to discard and reload less frequently needed segments on demand. Paging was obviously not used because there was no support for it in 8086 and 80286 systems (and before Windows 3.0, those were very nearly the entirety of the installed base).

In the simplest case of an application with one code segment and one data segment, the movable nature of Windows segments is almost entirely transparent. When the application is running, the CS (code) segment register points to the code segment and the DS (data) and SS (stack) segment registers point to the data segment. As long as the application only uses near calls/jumps within its code segment and near pointers to the data/stack segment, it does not care at all where exactly the segments are in memory, i.e. the actual values loaded into CS/DS/SS registers. Windows can move the segments around and everything will work fine.

But even beginning Windows programmers working through a Hello World style example very quickly start suspecting that life is not so simple in the land of 16-bit Windows. The window procedure must be declared as FAR PASCAL, which is fair enough given that it needs to conform to Windows calling conventions. But it also has to be exported from the application’s executable, otherwise the program won’t work properly. That is a concept entirely unfamiliar to non-Windows developers.

To help implement its memory management scheme, Windows adopted and extended the "New Executable" (NE) format first used by "DOS 4", better known as Multitasking DOS 4.0 and significantly different from PC DOS and MS-DOS 4.0/4.01. Unlike the DOS MZ executable format where an application is effectively a single binary blob, the NE format is segment oriented and each segment is stored on disk separately. That gives Windows the ability to load (or reload) individual segments and move them around in memory.

The NE format also supports imports and exports. Imports are used when an application needs to call external code, such as the OS itself. Exports are used for application code which is externally called.

A window procedure is one such externally called piece of code. It needs to be exported so that Windows can perform its magic on it. Said magic lets Windows fix up the window procedure prolog (entry sequence) so that it loads the application’s own data segment into the DS register.

Shifting Memory

Everything in Windows memory management revolves around segments, contiguous blocks of memory up to 64KB in size. In normal 8086 programming, each segment is identified by its segment address, which directly corresponds to its address in physical memory. Because most segments in Windows can be moved or discarded, they are instead...

windows memory segment management application segments

Related Articles