Chapter 12

Memory Management


CONTENTS


Introduction

Netscape provides a plug-in developer with a set of three memory management APIs. For Macintosh developers, these APIs allow plug-ins to force Netscape to release system memory. Windows and Macintosh developers both need the Navigator's memory APIs to implement the save feature used by both NPP_Destroy and NPP_New.

Windows 95 plug-in developers have many system memory management functions to choose from. Of these, some of the most interesting are direct access to virtual memory and memory mapped files.

The following APIs are covered in this chapter:

NPN_MemAlloc
NPN_MemFree
NPN_MemFlush

Netscape's Memory APIs

Netscape provides plug-in developers with some basic memory management APIs to facilitate a saved memory feature. In many cases, you won't have to use these provided APIs. If you want to take advantage of saved memory between instances and don't want to worry about freeing memory that was allocated by a nonpresent instance, these plug-in APIs are the way to go.

In some cases, aside from the save feature, Netscape's provided memory management APIs are essential. Consider a Macintosh with the virtual memory feature turned off. This configuration is quite common for Mac users. If your plug-in attempts a memory allocation via a standard system call, it might find no memory available to back up this request. Instead, use the NPN_MemAlloc method. On a resource-restricted system, this API frees memory from Netscape's cache to try to fulfill the memory request.

In the world of Windows, the preceding scenario can also be the case with virtual memory turned off or with a full hard drive.

Memory Allocation and Freeing

To allocate a block of memory from Netscape, simply call the method NPN_MemAlloc with the single parameter being the size of the requested memory block. To free this memory block, call the NPN_MemFree method with a pointer to the previously allocated block.

Flushing Navigator's Memory on the Macintosh

The Macintosh has a special API called NPN_MemFlush. This method is provided for cases when calling NPN_MemAlloc is not possible. System APIs on the Mac can cause indirect allocation of memory. If these fail because of lack of memory, your recourse is to flush out Netscape's cache using NPN_MemFlush to retrieve the necessary amount of memory. Call NPN_MemFlush repeatedly until it returns zero to free as much memory as possible from the Navigator.

Windows 95 Memory Management

In Windows 95, you might never need to use Netscape's memory management APIs. A failed memory request from Windows 95 usually indicates much bigger problems than can be solved with Navigator giving up whatever memory it has allocated for cache. Additionally, the new operator certainly doesn't know about using NPN_MemAlloc. Although a tricky C++ programmer could simply override the new operator, Microsoft's Foundation Class Library beat you to it. Saving data between plug-in instances is probably the only case in Windows 95 to use Netscape's memory management APIs.

Address Space of a Process

In Windows 95, your plug-in is part of the Navigator's process address space. Each process has its own address space totally independent of other processes. Your plug-in's process, which is shared with Netscape, has a 2GB range of addresses for memory allocation. In addition to runtime memory allocation, your plug-in's DLL and the Netscape .EXE file are loaded in this range of addresses.

Although a 32-bit pointer can address 4GB of memory, a Windows 95 process can only access 2GB. The rest of the address range is used by page tables, VxDs, system DLLs, memory mapped files, 16-bit Windows support, and MS-DOS. Figure 12.1 shows the process address space for Windows 95.

Figure 12.1 : Windows 95 process address space.

Advanced Memory API

Windows 95 provides many layers of memory management. These layers support such things as Windows 3.x, C Runtime Memory Functions, Heap Manager API, Virtual Memory API, and Memory Mapped File API. At the end of all this is either your hard disk or physical memory. Figure 12.2 shows layered memory management for Win32.

Figure 12.2 : Windows 95 memory management layers.

Which Memory Management Functions to Use

With all those layers, it can be somewhat overwhelming to figure out what to use for plug-in development. In most cases, the new and delete operators combined with malloc and free are all you need. However, there are some really interesting memory management APIs that a Windows 95 developer might want to take advantage of-in particular, the Virtual Memory API and the Memory Mapped File API.

Using Virtual Memory Directly

Windows 95 manages virtual memory in what are called pages, or 4096-byte sections. Each of these pages can be in memory or swapped to disk at any given time. An address within your Windows 95 application really references a set of page tables. A 32-bit address within your process is broken down into a page directory index, page table index, and page index. The first 10 bits are the directory index, the next 10 bits are the table index, and the last 12 bits are the page index.

The following example shows how a virtual address of 0x009c8788 is resolved into directory, table, and page indices:

Address = 0x009C8788 (in hex)
Address = 0000 0000 1001 1100 1000 0111 1000 1000 (in binary)

Directory Index = 0000 0000 10
Table Index = 01 1100 1000
Page Index = 0111 1000 1000

The problem with using virtual memory without any heap management functions is that any allocation-even 1 byte-will allocate a page of 4096 bytes. Fortunately, the C runtime does a nice job of suballocating these pages for you with the help of the Heap Memory API.

Although malloc is great for small chunks of memory, what if you require a very large memory allocation? For example, if you know that you need at least 1MB of memory but definitely no more than 100MB, it would be nice to keep this memory as a contiguous range of addresses. If you allocate 100MB with malloc, memory is immediately committed and your swap file probably grows accordingly. Using a virtual memory API such as VirtualAlloc enables you to reserve the 100MB range but only commit it as necessary. The 100MB limit might seem like a lot, but remember that your process can address 2GB; 100MB is only about five percent of that, and the memory address range is just reserved and uses no system resources.

Using a Memory Mapped File

With all that address space within your process, another Windows 95 feature called memory mapped files is possible. Memory mapped files allow you to map a file to your process's address space and access the file through pointers as if it is memory. Because a very large memory mapped file is read into memory by Windows in only 4096 byte pages, resource use is minimized and the application benefits by seeing the whole file in memory. A memory mapped file is also allocated in shared memory, which allows interprocess communication.

Note
The Microsoft Developer Network CD-ROMs are an excellent source of information on advanced Windows 95 memory management features.

Old Friends: LocalAlloc and GlobalAlloc

If you are coming from a Windows 3.x programming background, as most Windows 95 programmers are, you might be tempted to use LocalAlloc and GlobalAlloc instead of the C Runtime routine malloc. In the past, many problems occurred with malloc for Windows 16-bit programming. With Windows 95, you can safely use malloc and free. In fact, LocalAlloc and GlobalAlloc are somewhat obsolete and both resolve to the same routine within the Windows kernel. Keep in mind that Windows 95 has a 32-bit flat memory module with no concept of near or far pointers. Also, because in MFC C++ the new operator resolves to a malloc, you really can't avoid using malloc even if you want to.

Your Plug-In as a Windows 95 DLL

A Windows 95 plug-in is implemented as a Dynamic Link Library (DLL). Unlike Windows 3.x, a Windows 95 DLL data segment is not shared by default. In most cases, you won't care whether your plug-in is loaded by another process. Although it is very rare for a user to bring up another copy of Netscape and load your plug-in through another process, you still need to handle this case.

If your plug-in will have catastrophic failure when loaded by another process, you should keep track of how many times the plug-in is loaded. A simple way to do this is by creating an additional data segment within your DLL and setting it to SHARED. Use the SECTIONS keyword in your .DEF file and name your new segment as follows:

SECTIONS .newseg READ WRITE SHARED

In your C code, use pragmas to define any variables in this new segment:

#pragma data_seg (".newseg")
int ProcessCount = 0;
#pragma data_seg ()

Make sure to initialize any variables in this new segment, or they will be put in the uninitialized data section. Use the NPP_Initialize and NPP_Shutdown methods accordingly to increment and decrement a process count.

API Quick Reference

The following sections give in-depth information on the APIs used in this chapter.

NPN_MemAlloc

CompatibilityWindows 3.1/95/NT, Macintosh, UNIX.
API TypeNavigator implemented method.
PurposeCalled from the plug-in to allocate memory within the Navigator's memory space.
Syntaxvoid* NPN_MemAlloc (uint32 size)

uint32 size: An unsigned long indicating the size of memory for allocation.

Includes#include <npapi.h>
DescriptionNPN_MemAlloc is called from the plug-in to request a block of memory from the Navigator. This method is only needed for cases in which the plug-in might not have the opportunity to free the memory block. One such case is the NPP_Destroy method's save option. When your plug-in allocates memory for this feature, it must allocate the memory with NPN_MemAlloc to guarantee eventual freeing of the memory block. If your plug-in is never called again, the Navigator ensures that memory is freed.
Returnsvoid*: A pointer to the allocated memory block.
See AlsoNPN_MemFlush (Macintosh only), NPN_MemFree
Example//
//
Use NPN_MemAlloc for a saved memory block //
.
.
.
     // First allocate the structure for saved data
      MySavedData* mysaveddata = (MySavedData*)NPN_MemAlloc
Â(sizeof(MySavedData));
      // Then allocate a NPSavedData structure
      (*save) = (NPSavedData *)NPN_MemAlloc (sizeof(NPSavedData));
     (*save)->buf = mysaveddata;
     (*save)->len = sizeof(MySavedData);

.
.
.

NPN_MemFree

CompatibilityWindows 3.1/95/NT, Macintosh, UNIX.
API TypeNavigator implemented method.
PurposeCalled from the plug-in to free memory previously allocated with the NPN_MemAlloc method.
Syntaxvoid NPN_MemFree (void* ptr)

void* ptr: A pointer to a memory block allocated with NPN_MemAlloc.

Includes#include <npapi.h>
DescriptionUse NPN_MemFree to free a memory block that was allocated with NPN_MemAlloc. Make sure NPN_MemAlloc and NPN_MemFree are used as pairs. Do not attempt to use NPN_MemFree on a block of memory allocated with malloc or the new operator.
ReturnsNone.
See AlsoNPN_MemFlush (Macintosh only), NPN_MemAlloc
Example//
// Free a saved block of memory allocated with NPN_MemAlloc
//

.
.
.

if (saved)
{
     if (saved->len == sizeof (MySavedData)
     {
         MySavedData* mysaveddata = saved->buf;

         .         .  Get whatever you need…
         .

         // Free both memory blocks with NPN_MemFree

         NPN_MemFree (saved->buf);
         NPN_MemFree (saved);
     }
}
.
.
.

NPN_MemFlush

CompatibilityMacintosh only.
API TypeNavigator implemented method.
PurposeUsed to free memory in the Navigator and allow more memory for the plug-in.
Syntaxuint32 NPN_MemFlush (uint32 size)

uint32 size: An unsigned long indicating the amount of memory required by the plug-in.

Includes#include <npapi.h>
DescriptionIn the Macintosh environment, it is quite common to turn off virtual memory. This practice can lead to a memory-starved system. Netscape allocates some unessential memory for such things as cache that can be freed for use by the plug-in. In a regular call to NPN_MemAlloc, Navigator memory is freed to accommodate a plug-in's request. A Macintosh System API might also attempt to allocate memory. If these system allocations fail, the plug-in developer might call NPN_MemFlush to free more memory from the Navigator.

Call NPN_MemFlush repeatedly until it returns zero to request that the Navigator free as much memory as possible.

ReturnsNone.
See AlsoNPN_MemAlloc, NPN_MemFree
Example//
// Get the maximum amount of memory from the Navigator with NPN_MemFlush
//

.
.
.

     while (NPN_MemFlush (0xFFFF));

.
.

Conclusion

Of the plug-in memory management APIs, NPN_MemAlloc and NPN_MemFree are used by the Windows, UNIX, and Macintosh environments, and the NPN_MemFlush API is used in the Macintosh environment only.

In most cases, these methods are used for the purposes of allocating and freeing memory to use in saves between plug-in instances.

The NPN_MemFlush method allows the Macintosh plug-in to request that Navigator free any noncritical memory.

What's Next?

Netscape provides a method to give the browser user plug-in status and another method to query the user agent field. The NPN_Status and NPN_UserAgent methods are covered in the next chapter.