243 lines
16 KiB
HTML
243 lines
16 KiB
HTML
<!-- BeginDsi "dsi/head.html" -->
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Embedthis Appweb 4.3.4 Documentation</title>
|
|
<meta name="keywords" content="embedded web server, web server software, embedded HTTP, application web server,
|
|
embedded server, small web server, HTTP server, library web server, library HTTP, HTTP library" />
|
|
<meta name="description" content="Embedthis Sofware provides commercial and open source embedded web servers for
|
|
devices and applications." />
|
|
<meta name="robots" content="index,follow" />
|
|
<link href="../../doc.css" rel="stylesheet" type="text/css" />
|
|
<link href="../../print.css" rel="stylesheet" type="text/css" media="print"/>
|
|
<!--[if IE]>
|
|
<link href="../../iehacks.css" rel="stylesheet" type="text/css" />
|
|
<![endif]-->
|
|
<link href="http://www.google.com/cse/style/look/default.css" type="text/css" rel="stylesheet" />
|
|
</head>
|
|
|
|
<body>
|
|
<div class="top">
|
|
<a class="logo" href="http://appwebserver.org/"> </a>
|
|
<div class="topRight">
|
|
<div class="search">
|
|
<div id="cse-search-form"></div>
|
|
<div class="version">Embedthis Appweb 4.3.4</div>
|
|
</div>
|
|
</div>
|
|
<div class="crumbs">
|
|
<a href="../../index.html">Home</a>
|
|
<!-- EndDsi -->
|
|
> <a href="index.html">Programmers Reference</a> > <b>Architecture</b>
|
|
</div>
|
|
</div>
|
|
<div class="content">
|
|
<div class="contentRight">
|
|
<h1>Quick Nav</h1>
|
|
<ul>
|
|
<li><a href="#overview">Overview</a></li>
|
|
<li><a href="#allocator">Allocator</a></li>
|
|
<li><a href="#errors">Error Handling</a></li>
|
|
<li><a href="#collector">Garbage Collector</a></li>
|
|
<li><a href="#phases">Collection Phases</a></li>
|
|
<li><a href="#marking">Marking Blocks</a></li>
|
|
<li><a href="#alloc">Allocating Memory</a></li>
|
|
<li><a href="#managers">Managers</a></li>
|
|
</ul>
|
|
<h1>See Also</h1>
|
|
<ul>
|
|
<li><a href="multithread.html">Multithreaded</a></li>
|
|
<li><a href="architecture.html">Appweb Architecture</a></li>
|
|
<li><a href="../../guide/appweb/overview.html">User Guide Overview</a></li>
|
|
<li><a href="../../guide/appweb/users/authentication.html">Authorization</a></li>
|
|
<li><a href="../../guide/appweb/users/configuration.html">Configuration</a></li>
|
|
<li><a href="../../guide/appweb/users/configuration.html#directives">Configuration Directives</a></li>
|
|
<li><a href="../../guide/appweb/users/stages.html">Pipeline Stages</a></li>
|
|
<li><a href="../../guide/appweb/users/client.html">HTTP Client</a></li>
|
|
<li><a href="../../guide/appweb/users/modules.html">Loadable Modules</a></li>
|
|
<li><a href="../../guide/appweb/users/ports.html">Ports and Binding</a></li>
|
|
<li><a href="../../guide/appweb/users/ssl.html">Secure Sockets Layer</a></li>
|
|
<li><a href="../../guide/appweb/users/vhosts.html">Virtual Hosts</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="contentLeft">
|
|
<h1>MPR Memory Allocator</h1>
|
|
<a id="overview"></a>
|
|
<h2>Overview</h2>
|
|
<p>Appweb provides an application-specific memory allocator to use instead of malloc. This allocator is
|
|
part of the Multithreaded Portable Runtime (MPR) and is tailored to the needs of embedded applications.
|
|
It is faster than most general purpose malloc allocators for these workloads. It is deterministic and
|
|
allocates and frees memory in constant time O(1). It exhibits very low fragmentation and accurate
|
|
coalescing.</p>
|
|
<p>The allocator uses a garbage collector for locating unused memory. The collector is a generational,
|
|
cooperative and non-compacting collector. The use of a garbage collector is somewhat unusual in a C program.
|
|
However, garbage collection it is especially well suited for long running applications like a web server,
|
|
as it eliminates most memory leaks. Unlike traditional memory allocation where <em>free</em> must be called
|
|
to release memory, Appweb uses the opposite approach. Memory that must be retained, must be actively managed to
|
|
prevent garbage collection. This means that a <em>managed reference</em> must be held for all active memory.</p>
|
|
<p>In practice there are thus two kinds of memory:</p>
|
|
<ul>
|
|
<li>Managed memory — This is memory allocated via the MPR which is actively managed by the
|
|
garbage collector. The user is responsible for marking the memory as being active via the mprMark API.
|
|
The collector will automatically reclaim the memory when it is no longer marked as being actively used.</li>
|
|
<li>Malloc memory — This is memory allocated directly or indirectly by malloc, and is not managed
|
|
by the garbage collector. The user is responsible for explicitly calling free() when the memory is
|
|
no longer required. You must not call mprMark() on such memory.</li>
|
|
</ul>
|
|
<a id="allocator"></a>
|
|
<h2>Allocator</h2>
|
|
<p>The allocator is optimized for frequent allocations of small blocks (< 4K). It
|
|
uses a scheme of free queues for fast allocation. Memory allocations are aligned on 16 byte boundaries on 64-bit
|
|
systems and otherwise on 8 byte boundaries. It will return chunks of unused memory back to the O/S.</p>
|
|
<h3>Appweb 3 Allocator</h3>
|
|
<p>Appweb 3 memory API required a memory context argument for all memory allocations. This required many
|
|
APIs to have a memory context as the first parameter. Appweb 4 does not require this and these APIs have
|
|
removed the memory context parameter.</p>
|
|
<a id="errors"></a>
|
|
<h2>Error Handling</h2>
|
|
<p> It is difficult for programmers to consistently
|
|
check the result of every API call that can fail due to memory allocation errors. Calls such as strdup and
|
|
asprintf are often assumed to succeed, but they can, and do fail when memory is depleted.</p>
|
|
<p>A better approach is to proactively detect and handle memory allocation errors in one place.
|
|
The MPR allocator handles memory allocation errors globally. It has
|
|
has a configurable memory redline limit and a memory depletion policy handler.
|
|
Appweb configures this memory limit so that memory depletion can be proactively detected and
|
|
handled before memory allocations actually fail.
|
|
When memory usage exceeds a pre-configured redline value, the depletion handler is invoked.
|
|
The application can then determine what action to take. Typically, Appweb will restart in such
|
|
circumstances.</p>
|
|
<a id="collector"></a>
|
|
<h2>Garbage Collection</h2>
|
|
<p>The MPR garbage collector will run periodically to reclaim unused memory and potentially return
|
|
that memory to the
|
|
Operating System. The collector runs in its own thread, but is cooperative, in that each other thread must
|
|
yield to the collector before memory can be reclaimed. Worker threads yield to the collector
|
|
by calling the <em>mprYield</em> API.
|
|
This strategy permits worker threads to allocate temporary memory without fear. The memory will not be
|
|
prematurely collected until the worker explicitly acknowledges and yields to the collector by
|
|
calling <em>mprYield</em>. Appweb will ensure threads call mprYield when waiting for I/O or when a request
|
|
is complete. Users only need to explicitly call mprYield when they are doing a long-blocking operation.</p>
|
|
<p>To prevent collection of a memory block and retain the block over a yield point, the application must
|
|
hold a managed reference for the block. A managed reference, is a reference to an allocated block that
|
|
will be marked as active by mprMark() during a collection cycle by the parent block's manager function.
|
|
Manager functions are defined when allocating blocks that will hold managed references. See below for more
|
|
details.</p>
|
|
<a id="phases"></a>
|
|
<h3>Collection Phases</h3>
|
|
<p>The collector reclaims memory in three phases: Wait, Mark and Sweep. The Wait phase waits for all
|
|
threads to yield. This quiesces the system for reliable collection. NOTE: this does not mean that all
|
|
request activity must cease. Rather, pre-determined rendezvous yield points are inserted in key locations
|
|
in the Appweb HTTP processing engine.</p>
|
|
<p>The Mark phase traverses memory and marks all blocks that are
|
|
currently being used. The Sweep phase finally reclaims all blocks that are not marked.</p>
|
|
<a id="marking"></a>
|
|
<h3>Marking Blocks</h3>
|
|
<p>The Mark phase beings with a set of known root memory blocks. The ultimate root is the Mpr object
|
|
returned from the <em>mprCreate</em> API. However, other roots can be added at any time
|
|
via <em>mprAddRoot</em>. For each root,
|
|
the collector invokes the manager function defined when the block was allocated. It is the responsibility of
|
|
that manager function to call <em>mprMark</em> on every managed reference owned by the block.
|
|
The mprMark function will then invoke the manager for these managed references and so on.
|
|
In this manner, managed memory forms a tree from the roots to the leaves and the mark phase visits every
|
|
managed block currently in use.</p>
|
|
<a id="alloc"></a>
|
|
<h3>Allocating Memory</h3>
|
|
<p>Managers are defined when allocating a block of memory. For example, this code will allocate a block
|
|
that will contain a reference to a managed string and a reference to an un-managed malloc block.</p>
|
|
<pre>
|
|
typedef struct MyBlock
|
|
char *managedString;
|
|
void *privateMalloc;
|
|
} MyBlock;
|
|
MyBlock *blk = mprAllocObj(MyBlock, manageBlock);
|
|
blk->managedString = sclone("Hello World");
|
|
blk->privateMalloc = malloc(1024);
|
|
</pre>
|
|
<p>This will allocate a new structure and define manageBlock as the manager function for the structure.
|
|
If you need to keep the allocated structure, you must ensure the <em>blk</em> reference will be marked
|
|
during the garbage collector mark phase. To do this, you must ensure the reference is marked via mprMark
|
|
during some other object's manager function. Alternatively, you can call mprAddRoot to specify that this
|
|
reference is a top level root of a new memory tree. You should do this sparingly. It is more effective
|
|
to mark the reference from another manager routine.</p>
|
|
<p>If you only require the allocated structure temporarily, you do not need to retain a reference or call
|
|
mprAddRoot. In this manner, the memory will be automatically collected during the next garbage collection
|
|
sweep because there will not be a managed (marked) reference to the block.</p>
|
|
<p>the mprAllocMem may be used to allocate a block of memory and reserve room for a manager function. Then use
|
|
mprSetManager to define a manager function.</p>
|
|
<a id="managers"></a>
|
|
<h3>Managers</h3>
|
|
<p>A manager function is invoked by the collector during each collector Mark phase of the collection cycle.
|
|
The manager is passed a reference to the block and a flags word. The flags are set to either MPR_MANAGE_MARK
|
|
during the Mark phase and to MPR_MANAGE_FREE if the collector determines the block is to be freed.</p>
|
|
<pre>
|
|
void manageBlock(MyBlock *blk, int flags)
|
|
{
|
|
if (flags & MPR_MANAGE_MARK) {
|
|
mprMark(blk->managedString);
|
|
/* Don't mark privateMalloc */
|
|
} else if (flags & MPR_MANAGE_FREE) {
|
|
/* Custom code when the block is freed */
|
|
}
|
|
}
|
|
</pre>
|
|
<p>Note that it is safe to call mprMark with NULL reference. This is a convenient patter so you do not
|
|
need to test if the element is null or not.
|
|
<h2>Convenient References</h2>
|
|
<p>Appweb defines two empty fields that can be used by request handlers to hold managed references. The
|
|
<em>HttpConn.data</em> field is marked by the HttpConn manager. A handler can store a managed-memory reference
|
|
in this field. The HttpConn manager will then call mprMark(conn->data) to mark the reference as active and
|
|
required.</p>
|
|
<p>Similarly, <em>HttpQueue.queueData</em> field is marked by the HttpQueue manager. A queue stage
|
|
(filter or handler) can store a managed-memory reference
|
|
in this field. The HttpQueue manager will then call mprMark(q->queueData) to mark the reference as active and
|
|
required.</p>
|
|
<p>Appweb defines two fields that can be used to store unmanaged memory references: HttpConn.staticData and HttpQueue.staticData. Use these to store references to memory allocated by malloc.</p>
|
|
<p>Another common technique it to define a top level application structure which will be the root memory block
|
|
for the entire application. Store top level managed references in this block and call mprAddRoot to define
|
|
it as a root block.</p>
|
|
<h2>Simple Rules</h2>
|
|
<p>Here are some simple rules for allocating memory with Appweb and using the Garbage Collector.</p>
|
|
<h3>Must Mark to Retain Managed Memory</h3>
|
|
<p>Any memory allocated from the MPR must be marked to retain past the next garbage collection cycle.</p>
|
|
<h3>Don't Mix Memory</h3>
|
|
<p>You must not mix MPR allocated memory and non-managed memory. This means don't mark un-managed memory
|
|
that has been allocated via malloc(). And you must not call free() on managed memory allocated from
|
|
the MPR.</h3>
|
|
<h3>Define a Manager</h3>
|
|
<p>If you allocate a managed structure that has references to managed memory, you should define a manager
|
|
function that invokes mprMark on the structure elements that are managed references.</p>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<!-- BeginDsi "dsi/bottom.html" -->
|
|
<div class="bottom">
|
|
<p class="footnote">
|
|
<a href="../../product/copyright.html" >© Embedthis Software LLC, 2003-2013.
|
|
All rights reserved. Embedthis, Appweb, ESP, Ejscript and Embedthis GoAhead are trademarks of Embedthis Software LLC.</a>
|
|
</p>
|
|
</div>
|
|
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
|
|
<script type="text/javascript">
|
|
google.load('search', '1', {language : 'en'});
|
|
google.setOnLoadCallback(function() {
|
|
var customSearchControl = new google.search.CustomSearchControl(
|
|
'000262706376373952077:1hs0lhenihk');
|
|
customSearchControl.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET);
|
|
var options = new google.search.DrawOptions();
|
|
options.enableSearchboxOnly("http://appwebserver.org/search.html");
|
|
customSearchControl.draw('cse-search-form', options);
|
|
}, true);
|
|
</script>
|
|
<script type="text/javascript">
|
|
var _gaq = _gaq || [];
|
|
_gaq.push(['_setAccount', 'UA-179169-2']);
|
|
_gaq.push(['_trackPageview']);
|
|
(function() {
|
|
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|