mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-04-27 16:51:06 -07:00
Write pool reference.
Copied from Perforce Change: 180165 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
200a7ef7f7
commit
9eb16d7111
17 changed files with 1261 additions and 400 deletions
|
|
@ -73,6 +73,10 @@ Memory Management Glossary: B
|
|||
These instructions are vital for certain synchronization
|
||||
operations.
|
||||
|
||||
barrier hit
|
||||
|
||||
.. see:: :term:`protection fault`.
|
||||
|
||||
base pointer
|
||||
|
||||
A *base pointer* is a :term:`pointer` to the base or start of
|
||||
|
|
|
|||
|
|
@ -136,7 +136,9 @@ Memory Management Glossary: D
|
|||
*dependent object*. While scanning an object, the MPS
|
||||
ensures that the dependent object is unprotected so that
|
||||
it can be updated. This feature supports the
|
||||
implementation of weak-key and weak-value hash tables.
|
||||
implementation of :term:`weak-key <weak-key hash table>`
|
||||
and :term:`weak-value hash tables`. See
|
||||
:ref:`pool-awl-dependent`.
|
||||
|
||||
derived pointer
|
||||
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ Memory Management Glossary: P
|
|||
|
||||
protection fault
|
||||
|
||||
.. aka:: *protection exception*, *protection violation*.
|
||||
.. aka:: *barrier hit*, *protection exception*, *protection violation*.
|
||||
|
||||
A protection fault is an exception or trap which occurs when a
|
||||
process attempts to access :term:`memory (2)` which has been
|
||||
|
|
|
|||
|
|
@ -420,6 +420,22 @@ Memory Management Glossary: R
|
|||
|
||||
.. bibref:: [UNGAR84]_, [JONES96]_.
|
||||
|
||||
remote reference
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
A :term:`reference` that logically belongs to a
|
||||
:term:`formatted object` and so must be :term:`fixed` when
|
||||
the object is :term:`scanned <scan>`, but which is not
|
||||
stored within the block containing the object. (For
|
||||
example, in an auxiliary table of some sort.)
|
||||
|
||||
The MPS does not generally support remote references
|
||||
because those references may be :term:`protected
|
||||
<protection>` and so if :term:`scan method` attempts to
|
||||
:term:`fix` them this will hit a :term:`barrier (1)` and
|
||||
cause a re-entrant call to the MPS.
|
||||
|
||||
replicating garbage collector
|
||||
|
||||
A variant of :term:`copying garbage collection`, which does
|
||||
|
|
|
|||
|
|
@ -3,33 +3,93 @@
|
|||
`<https://info.ravenbrook.com/project/mps/master/manual/wiki/pool_classes.html>`_
|
||||
`<https://info.ravenbrook.com/project/mps/master/design/poolamc/>`_
|
||||
|
||||
.. index::
|
||||
single: AMC; introduction
|
||||
single: pool class; AMC
|
||||
|
||||
.. _pool-amc:
|
||||
|
||||
==============================
|
||||
AMC (Automatic Mostly-Copying)
|
||||
==============================
|
||||
|
||||
General-purpose automatic (collecting) pool class. This is the most 'advanced' pool class in the MPS, intended for most client objects.
|
||||
**AMC** is a general-purpose :term:`automatically managed <automatic
|
||||
memory management>` :term:`pool class`. This is the most "advanced"
|
||||
pool class in the MPS, intended for the majority of objects in the
|
||||
client program. Use this pool class unless you need a particular
|
||||
feature that it doesn't provide.
|
||||
|
||||
AMC is "Automatic, Mostly Copying": it uses copying collection except when prevented by ambiguous references. It is generational.
|
||||
"Mostly Copying" means that it uses :term:`copying garbage collection`
|
||||
except for blocks that are :term:`pinned <pinning>` by
|
||||
:term:`ambiguous references`.
|
||||
|
||||
Chain: specify capacity and mortality of generations 0..N-1. Survivors from N-1 get promoted into an arena-wide topGen (often anachronistically called the "dynamic" generation).
|
||||
It uses :term:`generational garbage collection`. That is, it exploits
|
||||
assumptions about object lifetimes and inter-connection variously
|
||||
referred to as "the generational hypothesis". In particular, the
|
||||
following tendencies will be efficiently exploited by an AMC pool:
|
||||
|
||||
- most objects die young;
|
||||
|
||||
- objects that don't die young will live a long time;
|
||||
|
||||
- most references are "backwards in time" (from younger objects to
|
||||
older objects).
|
||||
|
||||
In the pool's :term:`generation chain`, specify the capacity and
|
||||
mortality of generations 0 to *n*\−1. Survivors from generation *n*\−1
|
||||
get promoted into an arena-wide "top" generation.
|
||||
|
||||
|
||||
An AMC pool is both scannable and collectable. Objects may contain exact references to other objects that will preserve such other objects. Objects may be reclaimed if they are not reachable from a root. Objects may move during collection, unless reachable via a (direct) ambiguous reference. Objects in an AMC pool may be registered for finalization. Exact (that is, non-ambiguous)references into an object in an AMC pool must be to the start of the object.
|
||||
.. index::
|
||||
single: AMC; properties
|
||||
|
||||
The AMC pool class exploits assumptions about object lifetimes and inter-connection variously referred to as "the generational hypothesis". In particular, the following tendencies will be efficiently exploited by such a pool:
|
||||
AMC properties
|
||||
--------------
|
||||
|
||||
- Most objects die young;
|
||||
* Does not support allocation via :c:func:`mps_alloc` or deallocation
|
||||
via :c:func:`mps_free`.
|
||||
|
||||
- Objects that don't die young will live a long time;
|
||||
* Supports allocation via :term:`allocation points`. If an allocation
|
||||
point is created in an AMC pool, the call to :c:func:`mps_ap_create`
|
||||
takes no additional parameters.
|
||||
|
||||
- Most references are backwards in time.
|
||||
* Supports :term:`allocation frames` but does not use them to improve
|
||||
the efficiency of stack-like allocation.
|
||||
|
||||
:c:func:`mps_ap_frame_push` and :c:func:`mps_ap_frame_pop` may be used on an allocation point in an AMC pool.They do not declare the affected objects to be definitely dead (compare with the SNC pool class),but have an undefined effect on the collection strategy.
|
||||
* Does not support :term:`segregated allocation caches`.
|
||||
|
||||
If an allocation point is created in an AMC pool, the call to :c:func:`mps_ap_create` will take no additional parameters.
|
||||
* Garbage collections are scheduled automatically. See
|
||||
:ref:`topic-collection-schedule`.
|
||||
|
||||
* Blocks may contain :term:`exact references` to blocks in the same or
|
||||
other pools (but may not contain :term:`ambiguous references` or
|
||||
:term:`weak references (1)`, and may not use :term:`remote
|
||||
references`).
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is configurable.
|
||||
|
||||
* Blocks do not have :term:`dependent objects`.
|
||||
|
||||
* Blocks that are not :term:`reachable` from a :term:`root` are
|
||||
automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are :term:`scanned <scan>`.
|
||||
|
||||
* Blocks may only be referenced by :term:`base pointers` (unless they
|
||||
belong to an object format of variant auto-header).
|
||||
|
||||
* Blocks may be protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks may :term:`move <moving garbage collector>`.
|
||||
|
||||
* Blocks may be registered for :term:`finalization`.
|
||||
|
||||
* Blocks must belong to an :term:`object format`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: AMC; interface
|
||||
|
||||
AMC interface
|
||||
-------------
|
||||
|
|
@ -57,9 +117,16 @@ AMC interface
|
|||
``chain`` specifies the :term:`generation chain` for the pool.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: AMC; introspection
|
||||
|
||||
AMC introspection
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscamc.h"
|
||||
|
||||
.. c:function:: void mps_amc_apply(mps_pool_t pool, mps_amc_apply_stepper_t f, void *p, size_t s)
|
||||
|
||||
Visit all :term:`formatted objects` in an AMC pool.
|
||||
|
|
|
|||
|
|
@ -2,28 +2,68 @@
|
|||
|
||||
`<https://info.ravenbrook.com/project/mps/master/manual/wiki/pool_classes.html>`_
|
||||
|
||||
.. index::
|
||||
single: AMCZ; introduction
|
||||
single: pool class; AMCZ
|
||||
|
||||
.. _pool-amcz:
|
||||
|
||||
=========================================
|
||||
AMCZ (Automatic Mostly-Copying Zero-rank)
|
||||
=========================================
|
||||
|
||||
**AMCZ** is a general-purpose :term:`automatically managed <automatic
|
||||
memory management>` :term:`pool class` for :term:`leaf objects`
|
||||
("zero-rank" objects that contain no references).
|
||||
|
||||
General-purpose leaf-only pool class (for objects that contain no references). A variant of AMC (the Z means "Zero rank", ie. containing no references).
|
||||
It is otherwise indentical to :ref:`pool-amc`.
|
||||
|
||||
AMCZ is intended for "simple" objects like numbers, characters, and
|
||||
strings. Segregating these objects into one or more AMCZ pools avoids
|
||||
the cost of scanning them that would be incurred if they were
|
||||
interleaved in a pool with objects containing references.
|
||||
|
||||
|
||||
.. index::
|
||||
single: AMCZ; properties
|
||||
|
||||
---------------------
|
||||
AMCZ symbol reference
|
||||
---------------------
|
||||
AMCZ properties
|
||||
---------------
|
||||
|
||||
AMCZ is indentical to :ref:`pool-amc`, except that:
|
||||
|
||||
* Blocks may not contain :term:`references`.
|
||||
|
||||
* Blocks are not :term:`scanned <scan>`. A consequence of this is that
|
||||
the pool's :term:`object format` need not provide a :term:`scan
|
||||
method`.
|
||||
|
||||
* Blocks are not protected by :term:`barriers (1)`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: AMCZ; interface
|
||||
|
||||
AMCZ interface
|
||||
--------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscamc.h"
|
||||
|
||||
|
||||
------------
|
||||
Undocumented
|
||||
------------
|
||||
|
||||
.. c:function:: mps_class_t mps_class_amcz(void)
|
||||
|
||||
Return the :term:`pool class` for an AMCZ (Automatic
|
||||
Mostly-Copying Zero-rank) :term:`pool`.
|
||||
|
||||
When creating an AMCZ pool, :c:func:`mps_pool_create` takes two
|
||||
extra arguments::
|
||||
|
||||
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
|
||||
mps_class_t mps_class_amcz(),
|
||||
mps_fmt_t fmt,
|
||||
mps_chain_t chain)
|
||||
|
||||
``fmt`` specifies the :term:`object format` for the objects
|
||||
allocated in the pool.
|
||||
|
||||
``chain`` specifies the :term:`generation chain` for the pool.
|
||||
|
|
|
|||
|
|
@ -3,23 +3,83 @@
|
|||
`<https://info.ravenbrook.com/project/mps/master/manual/wiki/pool_classes.html>`_
|
||||
`<https://info.ravenbrook.com/project/mps/master/design/poolams/>`_
|
||||
|
||||
.. index::
|
||||
single: AMS; introduction
|
||||
single: pool class; AMS
|
||||
|
||||
.. _pool-ams:
|
||||
|
||||
==============================
|
||||
AMS (Automatic Mark and Sweep)
|
||||
==============================
|
||||
|
||||
Non-moving automatic (collecting) pool class.
|
||||
**AMS** is an :term:`automatically managed <automatic memory
|
||||
management>` but :term:`non-moving <non-moving garbage collector>`
|
||||
:term:`pool class`. It should be used instead of :ref:`pool-amc` for
|
||||
blocks that need to be automatically managed, but cannot be moved.
|
||||
|
||||
AMS is "Automatic Mark & Sweep". Not generational.
|
||||
|
||||
Chain: specify capacity and mortality of 'generation' 0. [Why? Perhaps to trigger nursery-like collections? New 2001-03-02. RHSK 2006-11-27]
|
||||
AMS does not use :term:`generational garbage collection`, but when
|
||||
creating a pool you use a :term:`generation chain` to specify the
|
||||
capacity and mortality of a single "generation". These numbers are
|
||||
used to schedule the collection of the whole pool.
|
||||
|
||||
|
||||
.. index::
|
||||
single: AMS; properties
|
||||
|
||||
--------------------
|
||||
AMS symbol reference
|
||||
--------------------
|
||||
AMS properties
|
||||
--------------
|
||||
|
||||
* Does not support allocation via :c:func:`mps_alloc` or deallocation
|
||||
via :c:func:`mps_free`.
|
||||
|
||||
* Supports allocation via :term:`allocation points`. If an allocation
|
||||
point is created in an AMC pool, the call to :c:func:`mps_ap_create`
|
||||
takes no additional parameters.
|
||||
|
||||
* Supports :term:`allocation frames` but does not use them to improve
|
||||
the efficiency of stack-like allocation.
|
||||
|
||||
* Does not support :term:`segregated allocation caches`.
|
||||
|
||||
* Garbage collections are scheduled automatically. See
|
||||
:ref:`topic-collection-schedule`.
|
||||
|
||||
* Blocks may contain :term:`exact references` to blocks in the same or
|
||||
other pools (but may not contain :term:`ambiguous references` or
|
||||
:term:`weak references (1)`, and may not use :term:`remote
|
||||
references`).
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is configurable.
|
||||
|
||||
* Blocks do not have :term:`dependent objects`.
|
||||
|
||||
* Blocks that are not :term:`reachable` from a :term:`root` are
|
||||
automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are :term:`scanned <scan>`.
|
||||
|
||||
* Blocks may only be referenced by :term:`base pointers` (unless they
|
||||
belong to an object format of variant auto-header).
|
||||
|
||||
* Blocks are not protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks do not :term:`move <moving garbage collector>`. A consequence
|
||||
of this is that the pool's :term:`object format` need not provide a
|
||||
:term:`forward method`, an :term:`is-forwarded method` or a
|
||||
:term:`padding method`.
|
||||
|
||||
* Blocks may be registered for :term:`finalization`.
|
||||
|
||||
* Blocks must belong to an :term:`object format`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: AMS; interface
|
||||
|
||||
AMS interface
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -46,8 +106,21 @@ AMS symbol reference
|
|||
must have a single generation.
|
||||
|
||||
|
||||
------------
|
||||
Undocumented
|
||||
------------
|
||||
|
||||
.. c:function:: mps_class_t mps_class_ams_debug(void)
|
||||
|
||||
A :ref:`debugging <topic-debugging>` version of the AMS pool
|
||||
class.
|
||||
|
||||
When creating a debugging AMS pool, :c:func:`mps_pool_create`
|
||||
takes three extra arguments::
|
||||
|
||||
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
|
||||
mps_class_t mps_class_ams_debug(),
|
||||
mps_debug_option_s debug_option,
|
||||
mps_fmt_t fmt,
|
||||
mps_chain_t chain)
|
||||
|
||||
``debug_option`` specifies the debugging options. See
|
||||
:c:type:`mps_debug_option_s`.
|
||||
|
||||
``fmt`` and ``chain`` are the same as for :c:func:`mps_class_ams`.
|
||||
|
|
|
|||
|
|
@ -2,68 +2,334 @@
|
|||
|
||||
`<https://info.ravenbrook.com/project/mps/master/manual/wiki/pool_classes.html>`_
|
||||
`<https://info.ravenbrook.com/project/mps/master/design/poolawl/>`_
|
||||
`<http://info.ravenbrook.com/mail/2003/03/17/13-51-24/0.txt>`_
|
||||
DRJ: `<https://info.ravenbrook.com/mail/2003/03/17/13-51-24/0.txt>`_
|
||||
NB: `<https://info.ravenbrook.com/mail/2002/04/12/15-52-29/0.txt>`_
|
||||
NB: `<https://info.ravenbrook.com/mail/2002/04/12/15-56-15/0.txt>`_
|
||||
|
||||
.. index::
|
||||
single: AWL; introduction
|
||||
single: pool class; AWL
|
||||
|
||||
.. _pool-awl:
|
||||
|
||||
===========================
|
||||
AWL (Automatic Weak Linked)
|
||||
===========================
|
||||
|
||||
**AWL** is an :term:`automatically managed <automatic memory
|
||||
management>` :term:`pool class` that may contain :term:`weak
|
||||
references (1)`.
|
||||
|
||||
Automatic Weak Linked
|
||||
The purpose of this pool class is to allow the client to implement
|
||||
:term:`weak-key <weak-key hash table>`, :term:`weak-value <weak-value
|
||||
hash table>`, and :term:`doubly weak hash tables`.
|
||||
|
||||
For weak references, linked to normal references. The purpose of this pool class is to allow the client to implement hash tables (or, conceivably some similar datastructures) that are partly or wholly weak. A client might want a weak-key strong-value table, or a strong-key weak-value table (or in fact weak-key weak-value). For example, Java's java.util.WeakHashMap class.
|
||||
In a weak-key hash table, the keys are weakly referenced, so their
|
||||
presence in the table will not prevent the key object from being
|
||||
garbage collected. Once the key is no longer :term:`reachable`, weak
|
||||
references to it may get :dfn:`splatted` (that is, replaced with null
|
||||
pointers). Once that has happened, the client program can't get at the
|
||||
value corresponding to the key any more, so the implementation is free
|
||||
to splat the value slot as well.
|
||||
|
||||
The principle idea behind a weak-key strong-value hash table is that the keys are weakly referenced, so their presence in the table will not prevent the key object from being garbage collected. Once the key is no longer reachable, weak references to it may get splatted. Obviously once that has happened you can't get at the value corresponding to the key anymore, so the implementation is free to splat the value slot as well.
|
||||
AWL allows the implementation to splat the value slot at the same time
|
||||
that the weak key slot is splatted. (Or the other way around for
|
||||
weak-value tables.) See :ref:`pool-awl-dependent`.
|
||||
|
||||
Pool Class AWL allows the implementation to splat the value slot at the same time that the (weak) key slot is splatted. (Or the other way around if you have strong-key weak-value tables).
|
||||
|
||||
Exactly how you do this is not yet well documented (but see below for more hints).
|
||||
.. index::
|
||||
single: AWL; properties
|
||||
|
||||
AWL has another special power: it enables better handing of barrier hits on weak objects. To explain the benefit we need to describe a problem first. The MPS uses a read-barrier to perform incremental garbage collection [@@ link to canned-for-client explanation of how a garbage collector works in broad terms]. When the client tries to read an object containing weak references the MPS may have protected it so that the MPS can process the object before the client gets to see it. The problem for weak objects is that the client may try and access the object at a point in the collection cycle when the MPS cannot yet determine the status of the objects that the weak object refers to. What the MPS does in this situation is assume that all the referenced objects are going to live. This assumption is correct but conservative; it may result in objects that are weakly referenced staying alive for longer than they need to. In the worst case this can result in a very large amount of memory being used by objects that are no longer needed.
|
||||
AWL properties
|
||||
--------------
|
||||
|
||||
In order to combat this problem the MPS sometimes does the following: Instead of processing the entire weak object and unprotecting it so that the client can access the object the MPS may emulate the processor instruction. When this happens the MPS doesn't process the entire weak object, it only processes the exact location that was being accessed (typically a single word), it emulates the processor instruction, and it keeps the object protected. This happens invisibly from the client's perspective, it's exactly as if the instruction executed as normal. The MPS instead of processing the entire object processes just a single word.
|
||||
* Does not support allocation via :c:func:`mps_alloc` or deallocation
|
||||
via :c:func:`mps_free`.
|
||||
|
||||
Naturally this emulation business is delicate and hairy and involves staring at the most badly written parts of low-level processor architecture manuals for days.
|
||||
* Supports allocation via :term:`allocation points`. If an allocation
|
||||
point is created in an AMC pool, the call to :c:func:`mps_ap_create`
|
||||
takes one additional parameter, a :term:`rank` of type
|
||||
:c:type:`mps_rank_t`. The rank must be either
|
||||
:c:func:`mps_rank_exact` (to allocate ordinary objects containing
|
||||
:term:`exact references`), or :c:func:`mps_rank_weak` (to allocate
|
||||
objects that contain weak references). For example::
|
||||
|
||||
Emulation of accesses to protected objects happens when:
|
||||
mps_ap_t ap;
|
||||
mps_res_t res;
|
||||
res = mps_ap_create(&ap, pool, mps_rank_weak());
|
||||
if (res != MPS_RES_OK) error("can't create allocation point");
|
||||
|
||||
The object is a weak object allocated in an AWL pool.
|
||||
The MPS is on Linux/IA-32 or Windows/IA-32. Extending this list to new (reasonable) operating systems should be tolerable (for example, OS X/IA-32), new processor architectures require more work.
|
||||
The processor instruction that is accessing the object is of a suitable simple form. The MPS doesn't contain an emulator for all possible instructions that might access memory, so it only recognises and emulates a few forms of instruction. Currently this is simple MOVs from memory to a register or vice-versa, but it's best not to rely on the details.
|
||||
Because of this emulation, AWL places a restriction on the format of objects allocated in it:
|
||||
* Supports :term:`allocation frames` but does not use them to improve
|
||||
the efficiency of stack-like allocation.
|
||||
|
||||
All slots in an object must either be a valid word-aligned reference, or the bottom bits of the word must be non-zero so that it does not look like an aligned pointer. "Aligned pointer" means a word whose numeric value (that is, treated as an unsigned integer) is a multiple of the architecture's natural word size (in bytes). In the very likely event that you're using a 32-bit machine that means that an aligned poiner is a multiple of 4 and its bottom 2 bits are both 0. Bottom line: pointers must be untagged and aligned, ints must be tagged with a non-zero tag.
|
||||
* Does not support :term:`segregated allocation caches`.
|
||||
|
||||
AWL is one of the few pools that can allocate objects that contain non-exact references. The mps_ap_create method when used with an AWL pool accepts an extra argument, which is a rank of type mps_rank_t. The rank is either MPS_RANK_EXACT (to allocate ordinary objects contained exact references), or MPS_RANK_WEAK (to allocate objects that contain weak references). Example::
|
||||
* Garbage collections are scheduled automatically. See
|
||||
:ref:`topic-collection-schedule`.
|
||||
|
||||
if(MPS_RES_OK != mps_ap_create(&weakap, tablepool, MPS_RANK_WEAK) {
|
||||
/* Error. */
|
||||
...
|
||||
* Blocks may contain :term:`exact references` or :term:`weak
|
||||
references (1)` to blocks in the same or other pools (but may not
|
||||
contain :term:`ambiguous references`, and may not use :term:`remote
|
||||
references`).
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is configurable.
|
||||
|
||||
* Blocks may have :term:`dependent objects`.
|
||||
|
||||
* Blocks that are not :term:`reachable` from a :term:`root` are
|
||||
automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are :term:`scanned <scan>`.
|
||||
|
||||
* Blocks may only be referenced by :term:`base pointers` (unless they
|
||||
belong to an object format of variant auto-header).
|
||||
|
||||
* Blocks may be protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks do not :term:`move <moving garbage collector>`. A consequence
|
||||
of this is that the pool's :term:`object format` need not provide a
|
||||
:term:`forward method`, an :term:`is-forwarded method` or a
|
||||
:term:`padding method`.
|
||||
|
||||
* Blocks may be registered for :term:`finalization`.
|
||||
|
||||
* Blocks must belong to an :term:`object format`.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: AWL; dependent object
|
||||
|
||||
.. _pool-awl-dependent:
|
||||
|
||||
Dependent objects
|
||||
-----------------
|
||||
|
||||
In order to support prompt deletion of values in a :term:`weak-key
|
||||
hash table` when the key is splatted (and prompt deletion of values in
|
||||
a :term:`weak-value hash table`), an AWL pool allows each object to
|
||||
have a :dfn:`dependent object`.
|
||||
|
||||
The dependent object is specified by a ``find_dependent`` function
|
||||
which is passed to :c:func:`mps_pool_create` when creating an AWL
|
||||
pool. This is a function of type :c:type:`mps_find_dependent_t` that
|
||||
takes the address of an object in the pool and returns the address of
|
||||
its dependent object (or a null pointer if there is no corresponding
|
||||
dependent object).
|
||||
|
||||
When :term:`scanning <scan>` an object in an AWL pool, the MPS ensures
|
||||
that the dependent object is not protected. This means that the
|
||||
:term:`scan method` in the pool's :term:`object format` can read or
|
||||
write the dependent object.
|
||||
|
||||
The way you would normally use this feature in a weak hash table would
|
||||
be to put the table's keys in one object, and its values in another.
|
||||
(This would be necessary in any case, because the MPS does not support
|
||||
a mixture of :term:`exact references` and :term:`weak references (1)`
|
||||
in the same object.) The dependent object for the keys objects is the
|
||||
values object, and vice versa (if necessary). The scan method looks
|
||||
out for the splatting of a reference, and when this is detected, it
|
||||
splats the corresponding reference in the dependent object.
|
||||
|
||||
For example::
|
||||
|
||||
typedef struct weak_array_s {
|
||||
struct weak_array_s *dependent;
|
||||
size_t length; /* actually length * 2 + 1 */
|
||||
obj_t slot[1];
|
||||
} weak_array_s, *weak_array_t;
|
||||
|
||||
typedef weak_table_s {
|
||||
type_s type; /* TYPE_WEAK_TABLE */
|
||||
weak_array_t keys, values;
|
||||
} weak_table_s, *weak_table_t;
|
||||
|
||||
mps_addr_t weak_array_find_dependent(mps_addr_t addr)
|
||||
{
|
||||
weak_array_t a = addr;
|
||||
return a->dependent;
|
||||
}
|
||||
...
|
||||
|
||||
mps_res_t weak_array_scan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
||||
{
|
||||
MPS_SCAN_BEGIN(ss) {
|
||||
while (base < limit) {
|
||||
weak_array_t a = base;
|
||||
size_t i, length = a->length >> 1;
|
||||
for (i = 0; i < length; ++i) {
|
||||
mps_addr_t p = a->slot[i];
|
||||
if (MPS_FIX1(ss, p)) {
|
||||
mps_res_t res = MPS_FIX2(ss, &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
if (p == NULL) {
|
||||
/* key/value was splatted: splat value/key too */
|
||||
a->dependent->slot[i] = NULL;
|
||||
}
|
||||
a->slot[i] = p;
|
||||
}
|
||||
}
|
||||
base += offsetof(weak_array_s, slot) + a->length * sizeof a->slot[0];
|
||||
}
|
||||
} MPS_SCAN_END(ss);
|
||||
return MPS_RES_OK;
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``length`` field of the ``weak_array_s`` structure contains
|
||||
the value ``length * 2 + 1`` so that it cannot be mistaken for a
|
||||
pointer. See :ref:`pool-awl-caution` below.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: AWL; protection faults
|
||||
|
||||
See also NB's notes on weak hash tables in Dylan:
|
||||
<https://info.ravenbrook.com/mail/2002/04/12/15-52-29/0.txt>
|
||||
<https://info.ravenbrook.com/mail/2002/04/12/15-56-15/0.txt>
|
||||
.. _pool-awl-barrier:
|
||||
|
||||
And DRJ's notes here: <https://info.ravenbrook.com/mail/2003/03/17/13-51-24/0.txt>
|
||||
Protection faults
|
||||
-----------------
|
||||
|
||||
AWL has another special power: it enables better handing of
|
||||
:term:`protection faults` on :dfn:`weak objects` (objects containing
|
||||
:term:`weak references (1)`).
|
||||
|
||||
To explain the benefit we first need to describe the problem. The MPS
|
||||
uses a :term:`read barrier` to perform :term:`incremental garbage
|
||||
collection`. When the client program tries to read an object
|
||||
containing :term:`weak references (1)`, the MPS may have
|
||||
:term:`protected <protection>` it so that the MPS can process the
|
||||
object before the client gets to see it.
|
||||
|
||||
The problem is that the client program may try to access a weak object
|
||||
at a point in the :term:`collection cycle` when the MPS cannot yet
|
||||
determine the status of the objects that the weak object refers to.
|
||||
What the MPS does in this situation is assume that all the referenced
|
||||
objects are going to live. This assumption is correct but
|
||||
conservative; it may result in objects that are weakly referenced
|
||||
staying alive for longer than they need to. In the worst case this can
|
||||
result in a very large amount of memory being used by objects that are
|
||||
no longer needed.
|
||||
|
||||
In order to combat this problem the MPS sometimes does the following:
|
||||
Instead of processing the entire weak object and unprotecting it, so
|
||||
that the client program can access the object, the MPS may emulate the
|
||||
processor instruction. When this happens, the MPS doesn't process the
|
||||
entire weak object; it only processes the exact location that was
|
||||
being accessed (typically a single word). It emulates the processor
|
||||
instruction, and it keeps the object protected. This happens invisibly
|
||||
from the client program's perspective: it's exactly as if the
|
||||
instruction executed as normal.
|
||||
|
||||
Naturally this emulation business is delicate and involves staring at
|
||||
the most badly written parts of low-level processor architecture
|
||||
manuals for days.
|
||||
|
||||
Emulation of accesses to protected objects happens when all of the
|
||||
following are true:
|
||||
|
||||
1. The object is a weak object allocated in an AWL pool.
|
||||
|
||||
2. The MPS is running on Linux/IA-32 or Windows/IA-32. Extending this
|
||||
list to new (reasonable) operating systems should be tolerable (for
|
||||
example, OS X/IA-32). Extending this to new processor architectures
|
||||
requires more work.
|
||||
|
||||
3. The processor instruction that is accessing the object is of a
|
||||
suitable simple form. The MPS doesn't contain an emulator for all
|
||||
possible instructions that might access memory, so currently it
|
||||
only recognizes and emulates a simple ``MOV`` from memory to a
|
||||
register or vice-versa.
|
||||
|
||||
:ref:`Contact us <contact>` if you need emulation of access to weak
|
||||
references for new operating systems, processor architectures, or
|
||||
memory access instructions.
|
||||
|
||||
|
||||
--------------------
|
||||
AWL symbol reference
|
||||
--------------------
|
||||
.. index::
|
||||
pair: AWL; cautions
|
||||
|
||||
.. _pool-awl-caution:
|
||||
|
||||
Caution
|
||||
-------
|
||||
|
||||
Because of the instruction emulation described in
|
||||
:ref:`pool-awl-barrier` above, AWL places the following restriction on
|
||||
the format of objects allocated in it:
|
||||
|
||||
* Each slot in an object must either be a valid word-aligned
|
||||
reference, or else the bottom bits of the word must be non-zero so
|
||||
that it does not look like an aligned pointer.
|
||||
|
||||
"Aligned pointer" means a word whose numeric value (that is, its
|
||||
value when treated as an unsigned integer) is a multiple of the
|
||||
architecture's natural :term:`word` size in :term:`bytes (1)`. If
|
||||
you're using a 32-bit architecture, that means that an aligned
|
||||
pointer is a multiple of 4 and its bottom two bits are both zero.
|
||||
|
||||
The bottom line is that references from an object in an AWL pool
|
||||
must be untagged and aligned, and integers must be tagged with a
|
||||
non-zero tag.
|
||||
|
||||
Normally one would cope with this restriction by allocating the table
|
||||
metadata in a pool belonging to another pool class, and only
|
||||
allocating the arrays of keys and values in an AWL pool. See :ref:`the
|
||||
example <pool-awl-dependent>` above.
|
||||
|
||||
|
||||
.. index::
|
||||
single: AWL; interface
|
||||
|
||||
AWL interface
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscawl.h"
|
||||
|
||||
|
||||
------------
|
||||
Undocumented
|
||||
------------
|
||||
|
||||
.. c:function:: mps_class_t mps_class_awl(void)
|
||||
|
||||
Return the :term:`pool class` for an AWL (Automatic Weak Linked)
|
||||
:term:`pool`.
|
||||
|
||||
When creating an AWL pool, :c:func:`mps_pool_create` takes two
|
||||
extra arguments::
|
||||
|
||||
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
|
||||
mps_class_t mps_class_awl(),
|
||||
mps_fmt_t fmt,
|
||||
mps_awl_find_dependent_t find_dependent)
|
||||
|
||||
``fmt`` specifies the :term:`object format` for the objects
|
||||
allocated in the pool.
|
||||
|
||||
``find_dependent`` is a function of type
|
||||
:c:type:`mps_awl_find_dependent_t` that specifies how to find the
|
||||
:term:`dependent object` for an object in the pool.
|
||||
|
||||
When creating an allocation point on an AWL pool,
|
||||
:c:func:`mps_ap_create` takes one extra argument::
|
||||
|
||||
mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
|
||||
mps_rank_t rank)
|
||||
|
||||
``rank`` specifies the :term:`rank` of references in objects
|
||||
allocated on this allocation point. It must be
|
||||
:c:func:`mps_rank_exact` (if the objects allocated on this
|
||||
allocation point will contain :term:`exact references`), or
|
||||
:c:func:`mps_rank_weak` (if the objects will contain :term:`weak
|
||||
references (1)`).
|
||||
|
||||
|
||||
.. c:type:: mps_addr_t (*mps_awl_find_dependent_t)(mps_addr_t addr)
|
||||
|
||||
The type of functions that find the :term:`dependent object` for
|
||||
an object in an AWL pool.
|
||||
|
||||
``addr`` is the address of an object in an AWL pool.
|
||||
|
||||
Returns the address of the corresponding dependent object, or a
|
||||
null pointer if there is none.
|
||||
|
||||
The dependent object need not be in memory managed by the MPS, but
|
||||
if it is, then it must be in a pool in the same arena as ``addr``.
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ Pool reference
|
|||
**************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
:maxdepth: 2
|
||||
|
||||
intro
|
||||
amc
|
||||
amcz
|
||||
ams
|
||||
|
|
@ -15,187 +17,3 @@ Pool reference
|
|||
mvff
|
||||
mvt
|
||||
snc
|
||||
|
||||
|
||||
.. _pool-choose:
|
||||
|
||||
Choosing a pool class
|
||||
=====================
|
||||
|
||||
This section contains a simple procedure for choosing a :term:`pool
|
||||
class` based on the properties of the data you plan to store in
|
||||
it. The MPS works well if you can segregate your data into a variety
|
||||
of pools, choosing the most appropriate pool class for each.
|
||||
|
||||
.. note::
|
||||
|
||||
Pool classes can differ in many ways not considered here: speed,
|
||||
vulnerability to fragmentation, control overhead, and so on. This
|
||||
procedure gives you a decent recommendation, but an expert in the
|
||||
MPS might be able to make a better one.
|
||||
|
||||
First, answer these questions about your data:
|
||||
|
||||
1. Do you need the MPS to :term:`automatically <automatic memory
|
||||
management>` :term:`reclaim` :term:`unreachable` blocks?
|
||||
|
||||
2. Is it acceptable for the MPS to :term:`move <moving memory
|
||||
manager>` blocks in memory and to place :term:`barriers (1)` on
|
||||
blocks? (For example, it might not be acceptable to move a block if
|
||||
it has been passed to :term:`foreign code` that remembered its
|
||||
location.)
|
||||
|
||||
3. Do your blocks contain :term:`references` to blocks stored in
|
||||
automatically managed pools (including references to other blocks
|
||||
in the same pool, if it's automatically managed)? And if so, are
|
||||
these references :term:`exact <exact reference>`, :term:`ambiguous
|
||||
<ambiguous reference>` or :term:`weak <weak reference (1)>`?
|
||||
|
||||
Second, look up your answers in this table to find the recommended
|
||||
pool class to use:
|
||||
|
||||
========== ====================== =========== ====================================
|
||||
Automatic? Movable & protectable? References? Use this pool class
|
||||
========== ====================== =========== ====================================
|
||||
yes yes none :ref:`pool-amcz`
|
||||
yes yes exact :ref:`pool-amc`
|
||||
yes yes ambiguous nothing suitable
|
||||
yes yes weak :ref:`pool-awl`
|
||||
yes no none :ref:`pool-lo`
|
||||
yes no exact :ref:`pool-ams`
|
||||
yes no ambiguous nothing suitable
|
||||
yes no weak nothing suitable
|
||||
no *any* none :ref:`pool-mvt`
|
||||
no *any* ambiguous :ref:`pool-mvt` [1]_
|
||||
no *any* exact :ref:`pool-mvt` [1]_
|
||||
no *any* weak :ref:`pool-mvt` [1]_
|
||||
========== ====================== =========== ====================================
|
||||
|
||||
.. note::
|
||||
|
||||
.. [1] :ref:`pool-mvt` doesn't scan for references, but you can
|
||||
work around this by registering your blocks as
|
||||
:term:`roots` (with the appropriate :term:`rank`) just
|
||||
after they are allocated, and deregistering them just
|
||||
before freeing them.
|
||||
|
||||
|
||||
.. Sources:
|
||||
|
||||
`<https://info.ravenbrook.com/project/mps/doc/2002-06-18/obsolete-mminfo/mmdoc/doc/mps/guide/pool-classes/>`_
|
||||
|
||||
.. _pool-properties:
|
||||
|
||||
Pool class properties
|
||||
=====================
|
||||
|
||||
This table summarizes the properties of each :term:`pool class`
|
||||
provided by the open source MPS. For "block" properties, "yes" means
|
||||
that the property holds for *all* blocks allocated from the pool. An
|
||||
entry "---" indicates that a property makes no sense for a pool class:
|
||||
for example, if blocks in a pool may not contain :term:`references`,
|
||||
it makes no sense to ask whether they may contain :term:`weak
|
||||
references (1)`.
|
||||
|
||||
|
||||
============================================= ===== ===== ===== ===== ===== ===== ===== ===== =====
|
||||
Property AMC AMCZ AMS AWL LO MV MVFF MVT SNC
|
||||
============================================= ===== ===== ===== ===== ===== ===== ===== ===== =====
|
||||
Supports :c:func:`mps_alloc`? no no no no no yes yes no ??
|
||||
Supports :c:func:`mps_free`? no no no no no yes yes yes ??
|
||||
Supports allocation points? yes yes yes yes yes no no yes ??
|
||||
Timing of collections? [2]_ auto auto yes auto auto --- --- --- ??
|
||||
May contain references? [3]_ yes no yes yes no no no no ??
|
||||
May contain exact references? [4]_ yes --- yes yes --- --- --- --- ??
|
||||
May contain ambiguous references? [4]_ no --- no no --- --- --- --- ??
|
||||
May contain weak references? [4]_ no --- no yes --- --- --- --- ??
|
||||
Allocations fixed or variable in size? var var var var var var var var ??
|
||||
Alignment? [5]_ conf conf conf conf conf [6]_ [7]_ [6]_ ??
|
||||
Dependent objects? [8]_ no --- no yes --- --- --- --- ??
|
||||
May use remote references? [9]_ no --- ?? no --- --- --- --- ??
|
||||
Ambiguous references keep blocks alive? no no ?? no no --- --- --- ??
|
||||
Blocks are automatically managed? [10]_ yes yes yes yes yes no no no ??
|
||||
Blocks are manually managed? [10]_ no no no no no yes yes yes ??
|
||||
Blocks are scanned? [11]_ yes no yes yes no no no no ??
|
||||
Blocks support base references only? [12]_ yes yes ?? yes yes --- --- --- ??
|
||||
Blocks support internal references? [12]_ no no ?? no no --- --- --- ??
|
||||
Blocks may be protected by barriers? yes no ?? yes no no no no ??
|
||||
Blocks may move? yes yes no no no no no no ??
|
||||
Blocks may be finalized? yes yes ?? yes yes no no no ??
|
||||
Blocks must be formatted? [11]_ yes yes yes yes yes no no no ??
|
||||
============================================= ===== ===== ===== ===== ===== ===== ===== ===== =====
|
||||
|
||||
.. note::
|
||||
|
||||
.. [2] "Timing of collections" is "auto" if :term:`garbage collection`
|
||||
is under the control of the MPS, which decides when collection
|
||||
should take place and performs it :term:`automatically
|
||||
<automatic memory management>` and :term:`incrementally
|
||||
<incremental garbage collection>`.
|
||||
|
||||
.. [3] Pools that may not contain references are suitable for
|
||||
storing :term:`leaf objects` only.
|
||||
|
||||
.. [4] Pools "may contain :term:`ambiguous <ambiguous reference>` /
|
||||
:term:`exact <exact reference>` / :term:`weak <weak
|
||||
reference (1)>` references" if the references that the client
|
||||
program fixes during scanning may include references of the
|
||||
indicated :term:`rank`.
|
||||
|
||||
.. [5] "Alignment" is "conf" if the client program may specify
|
||||
:term:`alignment` for each pool.
|
||||
|
||||
.. [6] The alignment of blocks allocated from :ref:`pool-mv` and
|
||||
:ref:`pool-mvt` pools is platform-dependent.
|
||||
|
||||
.. [7] :ref:`pool-mvff` pools have configurable alignment, but it may
|
||||
not be smaller than :c:macro:`MPS_PF_ALIGN` (the :term:`natural
|
||||
alignment` for the :term:`platform`).
|
||||
|
||||
.. [8] In pools with this property, each object may specify an
|
||||
:term:`dependent object` which the client program
|
||||
guarantees will be accessible during the scanning of the
|
||||
first object. This may be used in the implementation of
|
||||
:term:`weak hash tables`.
|
||||
|
||||
.. [9] "Remote references" are references that are stored outside the
|
||||
block to which they logically belong (for example, in some kind
|
||||
of auxiliary table). A pool containing remote references cannot
|
||||
rely on a :term:`write barrier` to detect changed references.
|
||||
|
||||
.. [10] Blocks are "automatically managed" if they may be
|
||||
automatically discarded when the MPS determines that they
|
||||
are unreachable; they are "manually managed" if they can be
|
||||
discarded when the :term:`client program` requests it. Note
|
||||
that these properties are not mutually exclusive, although
|
||||
the MPS does not provide a pool class that satisfies both.
|
||||
|
||||
.. [11] Blocks "are scanned" if the MPS :term:`scans` them for
|
||||
references; blocks "must be formatted" if they are
|
||||
described to the MPS by an :term:`object format`. At
|
||||
present, the MPS only knows how to scan blocks using the
|
||||
:term:`scan method` from an object format, but the MPS
|
||||
design does not preclude pools that scan unformatted
|
||||
blocks.
|
||||
|
||||
.. [12] A block "supports internal references" if a reference to any
|
||||
location within the block is considered to be a reference to
|
||||
the block. It "supports base references only" if only a
|
||||
reference to the base of the block is considered to be a
|
||||
reference to the block.
|
||||
|
||||
|
||||
Writing a new pool class
|
||||
========================
|
||||
|
||||
If none of the pool classes supplied with the MPS are quite right for
|
||||
your application, don't despair: the MPS is designed to be extensible
|
||||
with new pool classes, and designed so that the properties of pools
|
||||
are as orthogonal as possible. So if you need a pool containing
|
||||
objects that are scannable but unformatted, or movable objects which
|
||||
are manually managed, or a pool all of whose objects are roots, there
|
||||
is no technical reason why it should not be possible to write it.
|
||||
|
||||
If you'd be interested in our developing new pool classes for your
|
||||
requirements, or if you've started writing a new pool class
|
||||
yourself, :ref:`we'd love to hear from you <contact>`.
|
||||
|
|
|
|||
187
mps/manual/source/pool/intro.rst
Normal file
187
mps/manual/source/pool/intro.rst
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
.. _pool-choose:
|
||||
|
||||
Choosing a pool class
|
||||
=====================
|
||||
|
||||
This section contains a simple procedure for choosing a :term:`pool
|
||||
class` based on the properties of the data you plan to store in
|
||||
it. The MPS works well if you can segregate your data into a variety
|
||||
of pools, choosing the most appropriate pool class for each.
|
||||
|
||||
.. note::
|
||||
|
||||
Pool classes can differ in many ways not considered here: speed,
|
||||
vulnerability to fragmentation, control overhead, and so on. This
|
||||
procedure gives you a decent recommendation, but an expert in the
|
||||
MPS might be able to make a better one.
|
||||
|
||||
First, answer these questions about your data:
|
||||
|
||||
1. Do you need the MPS to :term:`automatically <automatic memory
|
||||
management>` :term:`reclaim` :term:`unreachable` blocks?
|
||||
|
||||
2. Is it acceptable for the MPS to :term:`move <moving memory
|
||||
manager>` blocks in memory and to place :term:`barriers (1)` on
|
||||
blocks? (For example, it might not be acceptable to move a block if
|
||||
it has been passed to :term:`foreign code` that remembered its
|
||||
location.)
|
||||
|
||||
3. Do your blocks contain :term:`references` to blocks stored in
|
||||
automatically managed pools (including references to other blocks
|
||||
in the same pool, if it's automatically managed)? And if so, are
|
||||
these references :term:`exact <exact reference>`, :term:`ambiguous
|
||||
<ambiguous reference>` or :term:`weak <weak reference (1)>`?
|
||||
|
||||
Second, look up your answers in this table to find the recommended
|
||||
pool class to use:
|
||||
|
||||
========== ====================== =========== ====================================
|
||||
Automatic? Movable & protectable? References? Use this pool class
|
||||
========== ====================== =========== ====================================
|
||||
yes yes none :ref:`pool-amcz`
|
||||
yes yes exact :ref:`pool-amc`
|
||||
yes yes ambiguous nothing suitable
|
||||
yes yes weak :ref:`pool-awl`
|
||||
yes no none :ref:`pool-lo`
|
||||
yes no exact :ref:`pool-ams`
|
||||
yes no ambiguous nothing suitable
|
||||
yes no weak nothing suitable
|
||||
no *any* none :ref:`pool-mvt`
|
||||
no *any* ambiguous :ref:`pool-mvt` [1]_
|
||||
no *any* exact :ref:`pool-mvt` [1]_
|
||||
no *any* weak :ref:`pool-mvt` [1]_
|
||||
========== ====================== =========== ====================================
|
||||
|
||||
.. note::
|
||||
|
||||
.. [1] :ref:`pool-mvt` doesn't scan for references, but you can
|
||||
work around this by registering your blocks as
|
||||
:term:`roots` (with the appropriate :term:`rank`) just
|
||||
after they are allocated, and deregistering them just
|
||||
before freeing them.
|
||||
|
||||
|
||||
.. Sources:
|
||||
|
||||
`<https://info.ravenbrook.com/project/mps/doc/2002-06-18/obsolete-mminfo/mmdoc/doc/mps/guide/pool-classes/>`_
|
||||
|
||||
.. _pool-properties:
|
||||
|
||||
Pool class properties
|
||||
=====================
|
||||
|
||||
This table summarizes the properties of each :term:`pool class`
|
||||
provided by the open source MPS. For "block" properties, "yes" means
|
||||
that the property holds for *all* blocks allocated from the pool. An
|
||||
entry "---" indicates that a property makes no sense for a pool class:
|
||||
for example, if blocks in a pool may not contain :term:`references`,
|
||||
it makes no sense to ask whether they may contain :term:`weak
|
||||
references (1)`.
|
||||
|
||||
|
||||
============================================= ===== ===== ===== ===== ===== ===== ===== ===== =====
|
||||
Property AMC AMCZ AMS AWL LO MV MVFF MVT SNC
|
||||
============================================= ===== ===== ===== ===== ===== ===== ===== ===== =====
|
||||
Supports :c:func:`mps_alloc`? no no no no no yes yes no no
|
||||
Supports :c:func:`mps_free`? no no no no no yes yes yes no
|
||||
Supports allocation points? yes yes yes yes yes no yes yes yes
|
||||
Supports allocation frames? yes yes yes yes yes no yes yes yes
|
||||
Supports segregated allocation caches? no no no no no yes yes no no
|
||||
Timing of collections? [2]_ auto auto auto auto auto --- --- --- ---
|
||||
May contain references? [3]_ yes no yes yes no no no no yes
|
||||
May contain exact references? [4]_ yes --- yes yes --- --- --- --- yes
|
||||
May contain ambiguous references? [4]_ no --- no no --- --- --- --- no
|
||||
May contain weak references? [4]_ no --- no yes --- --- --- --- no
|
||||
Allocations fixed or variable in size? var var var var var var var var var
|
||||
Alignment? [5]_ conf conf conf conf conf [6]_ [7]_ [6]_ conf
|
||||
Dependent objects? [8]_ no --- no yes --- --- --- --- no
|
||||
May use remote references? [9]_ no --- no no --- --- --- --- no
|
||||
Ambiguous references keep blocks alive? no no no no no --- --- --- no
|
||||
Blocks are automatically managed? [10]_ yes yes yes yes yes no no no no
|
||||
Blocks are manually managed? [10]_ no no no no no yes yes yes yes
|
||||
Blocks are scanned? [11]_ yes no yes yes no no no no yes
|
||||
Blocks support base pointers only? [12]_ yes yes yes yes yes --- --- --- yes
|
||||
Blocks support internal pointers? [12]_ no no no no no --- --- --- no
|
||||
Blocks may be protected by barriers? yes no no yes no no no no no
|
||||
Blocks may move? yes yes no no no no no no no
|
||||
Blocks may be finalized? yes yes yes yes yes no no no no
|
||||
Blocks must be formatted? [11]_ yes yes yes yes yes no no no yes
|
||||
Blocks may belong to format auto-header? yes yes yes yes yes --- --- --- no
|
||||
============================================= ===== ===== ===== ===== ===== ===== ===== ===== =====
|
||||
|
||||
.. note::
|
||||
|
||||
.. [2] "Timing of collections" is "auto" if :term:`garbage collection`
|
||||
is under the control of the MPS, which decides when collection
|
||||
should take place and performs it :term:`automatically
|
||||
<automatic memory management>` and :term:`incrementally
|
||||
<incremental garbage collection>`.
|
||||
|
||||
.. [3] Pools that may not contain references are suitable for
|
||||
storing :term:`leaf objects` only.
|
||||
|
||||
.. [4] Pools "may contain :term:`ambiguous <ambiguous reference>` /
|
||||
:term:`exact <exact reference>` / :term:`weak <weak
|
||||
reference (1)>` references" if the references that the client
|
||||
program fixes during scanning may include references of the
|
||||
indicated :term:`rank`.
|
||||
|
||||
.. [5] "Alignment" is "conf" if the client program may specify
|
||||
:term:`alignment` for each pool.
|
||||
|
||||
.. [6] The alignment of blocks allocated from :ref:`pool-mv` and
|
||||
:ref:`pool-mvt` pools is platform-dependent.
|
||||
|
||||
.. [7] :ref:`pool-mvff` pools have configurable alignment, but it may
|
||||
not be smaller than :c:macro:`MPS_PF_ALIGN` (the :term:`natural
|
||||
alignment` for the :term:`platform`).
|
||||
|
||||
.. [8] In pools with this property, each object may specify an
|
||||
:term:`dependent object` which the client program
|
||||
guarantees will be accessible during the scanning of the
|
||||
first object. This may be used in the implementation of
|
||||
:term:`weak hash tables`.
|
||||
|
||||
.. [9] "Remote references" are references that are stored outside the
|
||||
block to which they logically belong (for example, in some kind
|
||||
of auxiliary table). A pool containing remote references cannot
|
||||
rely on a :term:`write barrier` to detect changed references.
|
||||
|
||||
.. [10] Blocks are "automatically managed" if they may be
|
||||
automatically discarded when the MPS determines that they
|
||||
are unreachable; they are "manually managed" if they can be
|
||||
discarded when the :term:`client program` requests it. Note
|
||||
that these properties are not mutually exclusive, although
|
||||
the MPS does not provide a pool class that satisfies both.
|
||||
|
||||
.. [11] Blocks "are scanned" if the MPS :term:`scans` them for
|
||||
references; blocks "must be formatted" if they are
|
||||
described to the MPS by an :term:`object format`. At
|
||||
present, the MPS only knows how to scan blocks using the
|
||||
:term:`scan method` from an object format, but the MPS
|
||||
design does not preclude pools that scan unformatted
|
||||
blocks.
|
||||
|
||||
.. [12] A block "supports internal pointers" if a pointer to any
|
||||
location within the block is considered to be a reference
|
||||
to the block. It "supports base pointers only" if only a
|
||||
pointer to the base of the block (or, if the block belongs
|
||||
to an object format of variant auto-header, a pointer just
|
||||
past the end of the header) is considered to be a reference
|
||||
to the block.
|
||||
|
||||
|
||||
Writing a new pool class
|
||||
========================
|
||||
|
||||
If none of the pool classes supplied with the MPS are quite right for
|
||||
your application, don't despair: the MPS is designed to be extensible
|
||||
with new pool classes, and designed so that the properties of pools
|
||||
are as orthogonal as possible. So if you need a pool containing
|
||||
objects that are scannable but unformatted, or movable objects which
|
||||
are manually managed, or a pool all of whose objects are roots, there
|
||||
is no technical reason why it should not be possible to write it.
|
||||
|
||||
If you'd be interested in our developing new pool classes for your
|
||||
requirements, or if you've started writing a new pool class
|
||||
yourself, :ref:`we'd love to hear from you <contact>`.
|
||||
|
|
@ -3,30 +3,98 @@
|
|||
`<https://info.ravenbrook.com/project/mps/master/manual/wiki/pool_classes.html>`_
|
||||
`<https://info.ravenbrook.com/project/mps/master/design/poollo/>`_
|
||||
|
||||
.. index::
|
||||
single: LO; introduction
|
||||
single: pool class; LO
|
||||
|
||||
.. _pool-lo:
|
||||
|
||||
==============
|
||||
LO (Leaf Only)
|
||||
==============
|
||||
|
||||
Non-moving, non-protecting, automatic (collecting), Leaf Only pool class (for objects that contain no references). Unit test: locv.c. RefMan: -undocumented-.
|
||||
**LO** is an :term:`automatically managed <automatic memory
|
||||
management>` :term:`pool class` for :term:`leaf objects` (objects that
|
||||
contain no references). It does not move or protect its objects.
|
||||
|
||||
This pool class should really be called "flat data that needs to be accessed by foreign code" -- it's ideal for allocating a buffer to pass to an operating system I/O call. It is not very fast. [Conversation with DRJ, 2006-07].
|
||||
This pool class is intended for unstructured data that needs to be
|
||||
accessed by :term:`foreign code`. It's ideal for allocating a buffer
|
||||
that needs to be passed to an operating system I/O function.
|
||||
|
||||
(For a general-purpose leaf-only pool see AMCZ).
|
||||
For leaf objects that can move and be protected, consider
|
||||
:ref:`pool-amcz` instead.
|
||||
|
||||
|
||||
-------------------
|
||||
LO symbol reference
|
||||
-------------------
|
||||
.. index::
|
||||
single: LO; properties
|
||||
|
||||
LO properties
|
||||
-------------
|
||||
|
||||
* Does not support allocation via :c:func:`mps_alloc` or deallocation
|
||||
via :c:func:`mps_free`.
|
||||
|
||||
* Supports allocation via :term:`allocation points`. If an allocation
|
||||
point is created in an AMC pool, the call to :c:func:`mps_ap_create`
|
||||
takes no additional parameters.
|
||||
|
||||
* Supports :term:`allocation frames` but does not use them to improve
|
||||
the efficiency of stack-like allocation.
|
||||
|
||||
* Does not support :term:`segregated allocation caches`.
|
||||
|
||||
* Garbage collections are scheduled automatically. See
|
||||
:ref:`topic-collection-schedule`.
|
||||
|
||||
* Blocks may not contain :term:`references`.
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is configurable.
|
||||
|
||||
* Blocks do not have :term:`dependent objects`.
|
||||
|
||||
* Blocks that are not :term:`reachable` from a :term:`root` are
|
||||
automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are not :term:`scanned <scan>`. A consequence of this is that
|
||||
the pool's :term:`object format` need not provide a :term:`scan
|
||||
method`.
|
||||
|
||||
* Blocks may only be referenced by :term:`base pointers` (unless they
|
||||
belong to an object format of variant auto-header).
|
||||
|
||||
* Blocks are not protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks do not :term:`move <moving garbage collector>`. A consequence
|
||||
of this is that the pool's :term:`object format` need not provide a
|
||||
:term:`forward method` or an :term:`is-forwarded method`. (It also
|
||||
does not need a :term:`padding method`.)
|
||||
|
||||
* Blocks may be registered for :term:`finalization`.
|
||||
|
||||
* Blocks must belong to an :term:`object format`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: LO; interface
|
||||
|
||||
LO interface
|
||||
------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpsclo.h"
|
||||
|
||||
|
||||
------------
|
||||
Undocumented
|
||||
------------
|
||||
|
||||
.. c:function:: mps_class_t mps_class_lo(void)
|
||||
|
||||
Return the :term:`pool class` for an LO (Leaf Only) :term:`pool`.
|
||||
|
||||
When creating an LO pool, :c:func:`mps_pool_create` takes one
|
||||
extra argument::
|
||||
|
||||
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
|
||||
mps_class_t mps_class_lo(),
|
||||
mps_fmt_t fmt)
|
||||
|
||||
``fmt`` specifies the :term:`object format` for the objects
|
||||
allocated in the pool.
|
||||
|
|
|
|||
|
|
@ -1,28 +1,68 @@
|
|||
.. index::
|
||||
single: MV; introduction
|
||||
single: pool class; MV
|
||||
|
||||
.. _pool-mv:
|
||||
|
||||
====================
|
||||
MV (Manual Variable)
|
||||
====================
|
||||
|
||||
The :term:`pool class` MV (Manual Variable) is a general-purpose class
|
||||
of :term:`manually managed <manual memory management>` pools that
|
||||
manage :term:`blocks` of variable size.
|
||||
**MV** is a general-purpose :term:`manually managed <manual memory
|
||||
management>` :term:`pool class` that manages :term:`blocks` of
|
||||
variable size.
|
||||
|
||||
It supports allocation via :c:func:`mps_alloc` and deallocation via
|
||||
:c:func:`mps_free`.
|
||||
.. warning::
|
||||
|
||||
It does not support :term:`allocation points`.
|
||||
:ref:`pool-mvt` or :ref:`pool-mvff` should be used instead.
|
||||
|
||||
|
||||
-------------------
|
||||
MV symbol reference
|
||||
-------------------
|
||||
.. index::
|
||||
single: MV; properties
|
||||
|
||||
MV properties
|
||||
-------------
|
||||
|
||||
* Support allocation via :c:func:`mps_alloc` and deallocation via
|
||||
:c:func:`mps_free`.
|
||||
|
||||
* Does not support allocation via :term:`allocation points`.
|
||||
|
||||
* Does not support :term:`allocation frames`.
|
||||
|
||||
* Supports :term:`segregated allocation caches`.
|
||||
|
||||
* There are no garbage collections in this pool.
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is not configurable (it is the
|
||||
natural :term:`word` size of the platform).
|
||||
|
||||
* Blocks do not have :term:`dependent objects`.
|
||||
|
||||
* Blocks are not automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are not :term:`scanned <scan>`.
|
||||
|
||||
* Blocks are not protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks do not :term:`move <moving garbage collector>`.
|
||||
|
||||
* Blocks may not be registered for :term:`finalization`.
|
||||
|
||||
* Blocks must not belong to an :term:`object format`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: MV; interface
|
||||
|
||||
MV interface
|
||||
------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscmv.h"
|
||||
|
||||
|
||||
.. c:function:: mps_class_t mps_class_mv(void)
|
||||
|
||||
Return the :term:`pool class` for an MV (Manual Variable)
|
||||
|
|
@ -32,23 +72,66 @@ MV symbol reference
|
|||
extra arguments::
|
||||
|
||||
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
|
||||
mps_class_t mps_class_mvff(),
|
||||
mps_class_t mps_class_mv(),
|
||||
mps_size_t extend_size,
|
||||
mps_size_t average_size,
|
||||
mps_size_t maximum_size)
|
||||
|
||||
|
||||
``extend_size`` is the :term:`size` of segment that the pool will
|
||||
request from the :term:`arena`.
|
||||
|
||||
``average_size`` and ``maximum size`` are the predicted average
|
||||
and maximum size of blocks that will be allocated from the pool.
|
||||
These are hints to the MPS: the pool will be less efficient if
|
||||
these are wrong.
|
||||
|
||||
|
||||
------------
|
||||
Undocumented
|
||||
------------
|
||||
.. c:function:: mps_class_t mps_class_mv_debug(void)
|
||||
|
||||
A :ref:`debugging <topic-debugging>` version of the MV pool
|
||||
class.
|
||||
|
||||
When creating a debugging MV pool, :c:func:`mps_pool_create`
|
||||
takes four extra arguments::
|
||||
|
||||
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
|
||||
mps_class_t mps_class_mv_debug(),
|
||||
mps_debug_option_s debug_option,
|
||||
mps_size_t extend_size,
|
||||
mps_size_t average_size,
|
||||
mps_size_t maximum_size)
|
||||
|
||||
``debug_option`` specifies the debugging options. See
|
||||
:c:type:`mps_debug_option_s`.
|
||||
|
||||
``extend_szie``, ``average_size`` and ``maximum_size`` are as
|
||||
documented in :c:func:`mps_class_mv`.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: MV; introspection
|
||||
|
||||
MV introspection
|
||||
----------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscmv.h"
|
||||
|
||||
.. c:function:: size_t mps_mv_free_size(mps_pool_t pool)
|
||||
|
||||
Return the total amount of free space in an MV pool.
|
||||
|
||||
``pool`` is the MV pool.
|
||||
|
||||
Returns the total free space in the pool, in :term:`bytes (1)`.
|
||||
|
||||
|
||||
.. c:function:: size_t mps_mv_size(mps_pool_t pool)
|
||||
.. c:function:: mps_class_t mps_class_mv_debug(void)
|
||||
|
||||
Return the total size of an MV pool.
|
||||
|
||||
``pool`` is the MV pool.
|
||||
|
||||
Returns the total size of the pool, in :term:`bytes (1)`. This
|
||||
is the sum of allocated space and free space.
|
||||
|
|
|
|||
|
|
@ -2,42 +2,94 @@
|
|||
|
||||
`<https://info.ravenbrook.com/project/mps/master/design/poolmvff/>`_
|
||||
|
||||
.. index::
|
||||
single: MVFF; introduction
|
||||
single: pool class; MVFF
|
||||
|
||||
.. _pool-mvff:
|
||||
|
||||
================================
|
||||
MVFF (Manual Variable First Fit)
|
||||
================================
|
||||
|
||||
**MVFF** :term:`manually manages <manual memory management>`
|
||||
variable-sized, unformatted objects. It uses the :term:`first fit`
|
||||
:term:`allocation policy` for blocks allocated via
|
||||
:c:func:`mps_alloc`.
|
||||
|
||||
Buffered allocation (:c:func:`mps_reserve` and :c:func:`mps_commit`) is also supported, but in that case, the policy is rather different: buffers are filled worst-fit, and allocation is always upwards from the base. The arenaHigh parameter regulates whether new segments are acquired at high or low addresses;the slotHigh and firstFit parameters do not affect buffered allocation. Buffered and unbuffered allocation can be used at the same time, but in that case, the first allocation point must be created before any call to :c:func:`mps_alloc`.
|
||||
It also supports buffered allocation (that is, allocation via
|
||||
:term:`allocation points`), and in this case, the allocation policy is
|
||||
different: the buffers are filled according to the :term:`worst fit`
|
||||
policy, and allocation always proceeds upwards from the base.
|
||||
|
||||
Cached allocation (:c:macro:`MPS_SAC_ALLOC` and :c:macro:`MPS_SAC_FREE`) is also supported, but in that case,the policy is a little different: allocation from the cache follows its own policy (typicallyfirst-fit), and only when the cache needs to acquire more blocks from the underlying MVFF pool does it use the usual algorithm to choose blocks for the cache.
|
||||
Buffered and unbuffered allocation can be used at the same time, but
|
||||
the first allocation point must be created before any call to
|
||||
:c:func:`mps_alloc`.
|
||||
|
||||
::
|
||||
It is usually not advisable to use buffered and unbuffered allocation
|
||||
on the same pool, because the worst-fit policy of buffer filling will
|
||||
grab all the large blocks, leading to severe fragmentation. If you
|
||||
need both forms of allocation, use two separate pools.
|
||||
|
||||
if(mps_pool_create(&pool, arena, mps_class_mvff(), 8 * 1024, 135, 4, 0, 0, 1)
|
||||
!= MPS_RES_OK)
|
||||
{
|
||||
printf("Error creating pool!");
|
||||
exit(2);
|
||||
}
|
||||
Note that using buffered allocation prevents (for obscure technical
|
||||
reasons) the pool from allocating across segment boundaries. This can
|
||||
cause added external fragmentation if objects are allocated that are a
|
||||
significant fraction of the segment size.
|
||||
|
||||
.. note::
|
||||
|
||||
If you need to allocate large objects in an MVFF pool,
|
||||
:ref:`contact us <contact>`.
|
||||
|
||||
|
||||
It is usually not advisable to use buffered and unbuffered allocation at the same time,because the worst-fit policy of buffer filling will grab all the large blocks, leading to severe fragmentation. Use two separate pools instead.
|
||||
.. index::
|
||||
single: MVFF; properties
|
||||
|
||||
Note that using buffered allocation prevents (for obscure technical reasons) the pool from allocating across segment boundaries. This can cause added external fragmentation if objects are allocated that are a significant fraction of the segment size. (This quirk will disappear in a future version.)
|
||||
MVFF properties
|
||||
---------------
|
||||
|
||||
* Supports allocation via :c:func:`mps_alloc`.
|
||||
|
||||
* Supports allocation via :term:`allocation points`.
|
||||
|
||||
* Supports deallocation via :c:func:`mps_free`.
|
||||
|
||||
* Supports :term:`allocation frames` but does not use them to improve
|
||||
the efficiency of stack-like allocation.
|
||||
|
||||
* Supports :term:`segregated allocation caches`.
|
||||
|
||||
* There are no garbage collections in this pool.
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is not configurable (it is the
|
||||
natural :term:`word` size of the platform).
|
||||
|
||||
* Blocks do not have :term:`dependent objects`.
|
||||
|
||||
* Blocks are not automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are not :term:`scanned <scan>`.
|
||||
|
||||
* Blocks are not protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks do not :term:`move <moving garbage collector>`.
|
||||
|
||||
* Blocks may not be registered for :term:`finalization`.
|
||||
|
||||
* Blocks must not belong to an :term:`object format`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: MVFF; interface
|
||||
|
||||
---------------------
|
||||
MVFF symbol reference
|
||||
---------------------
|
||||
MVFF interface
|
||||
--------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscmvff.h"
|
||||
|
||||
|
||||
.. c:function:: mps_class_t mps_class_mvff(void)
|
||||
|
||||
Return the :term:`pool class` for an MVFF (Manual Variable First
|
||||
|
|
@ -67,15 +119,63 @@ MVFF symbol reference
|
|||
to the pool's alignment. The minimum alignment supported by pools
|
||||
of this class is ``sizeof(void *)``.
|
||||
|
||||
``slot_high``, ``arena_high``, and ``first_fit`` are undocumented
|
||||
and may be set to (0, 0, 1) or (1, 1, 1). No other setting of
|
||||
these parameters is recommended.
|
||||
``slot_high`` is undocumented. It must have the same value as
|
||||
``arena_high``.
|
||||
|
||||
If ``arena_high`` is true, new segments for buffered allocation
|
||||
are acquired at high addresses; if false, at low addresses.
|
||||
|
||||
``first_fit`` is undocumented and must be set to true.
|
||||
|
||||
|
||||
------------
|
||||
Undocumented
|
||||
------------
|
||||
.. c:function:: mps_class_t mps_class_mvff_debug(void)
|
||||
|
||||
A :ref:`debugging <topic-debugging>` version of the MVFF pool
|
||||
class.
|
||||
|
||||
When creating a debugging MVFF pool, :c:func:`mps_pool_create`
|
||||
takes seven extra arguments::
|
||||
|
||||
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
|
||||
mps_class_t mps_class_mvff_debug(),
|
||||
mps_debug_option_s debug_option,
|
||||
mps_size_t extend_size,
|
||||
mps_size_t average_size,
|
||||
mps_align_t alignment,
|
||||
mps_bool_t slot_high,
|
||||
mps_bool_t arena_high,
|
||||
mps_bool_t first_fit)
|
||||
|
||||
``debug_option`` specifies the debugging options. See
|
||||
:c:type:`mps_debug_option_s`.
|
||||
|
||||
The other arguments are the same as for :c:func:`mps_class_mvff`.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: MVFF; introspection
|
||||
|
||||
MVFF introspection
|
||||
------------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscmvff.h"
|
||||
|
||||
.. c:function:: size_t mps_mvff_free_size(mps_pool_t mpspool)
|
||||
|
||||
Return the total amount of free space in an MVFF pool.
|
||||
|
||||
``pool`` is the MVFF pool.
|
||||
|
||||
Returns the total free space in the pool, in :term:`bytes (1)`.
|
||||
|
||||
|
||||
.. c:function:: size_t mps_mvff_size(mps_pool_t pool)
|
||||
.. c:function:: mps_class_t mps_class_mvff_debug(void)
|
||||
|
||||
Return the total size of an MVFF pool.
|
||||
|
||||
``pool`` is the MVFF pool.
|
||||
|
||||
Returns the total size of the pool, in :term:`bytes (1)`. This
|
||||
is the sum of allocated space and free space.
|
||||
|
|
|
|||
|
|
@ -2,103 +2,105 @@
|
|||
|
||||
`<https://info.ravenbrook.com/project/mps/master/design/poolmvt/>`_
|
||||
|
||||
.. index::
|
||||
single: MVT; introduction
|
||||
single: pool class; MVT
|
||||
|
||||
.. _pool-mvt:
|
||||
|
||||
==============================
|
||||
MVT (Manual Variable Temporal)
|
||||
==============================
|
||||
|
||||
The MVT pool class manually manages variable-sized, unformatted objects. The MVT pool uses an allocation policy termed "temporal fit". Temporal fit attempts to place consecutive allocations next to each other. It relies on delaying reuse as long as possible to permit freed blocks to coalesce, thus maximizing the number of consecutive allocations that can be co-located. Temporal fit permits a very fast allocator and a deallocator competitive in speed with all other known policies.
|
||||
**MVT** :term:`manually manages <manual memory management>`
|
||||
variable-sized, unformatted objects. It uses an :term:`allocation
|
||||
policy` termed :dfn:`temporal fit`.
|
||||
|
||||
|
||||
Temporal fit is intended to take advantage of knowledge of object lifetimes, either apriori knowledge or knowledge acquired by profiling. The best performance of the MVT pool will be achieved by allocating objects with similar expected deathtimes together.
|
||||
.. index::
|
||||
pair: MVT; temporal fit
|
||||
single: allocation policy; temporal fit
|
||||
|
||||
Temporal fit
|
||||
------------
|
||||
|
||||
Temporal fit attempts to place consecutive allocations next to each
|
||||
other. It relies on delaying reuse as long as possible to permit freed
|
||||
blocks to :term:`coalesce`, thus maximizing the number of consecutive
|
||||
allocations that can be co-located. Temporal fit permits a very fast
|
||||
allocator and a deallocator competitive in speed with all other known
|
||||
policies.
|
||||
|
||||
Temporal fit is intended to take advantage of knowledge of object
|
||||
:term:`lifetimes`, either *a priori* knowledge, or knowledge acquired
|
||||
by profiling. The best performance will be achieved by allocating
|
||||
objects with similar expected death times together.
|
||||
|
||||
A simple policy can be implemented to take advantage of MVT. Object
|
||||
size is typically well-correlated with object life-expectancy, and
|
||||
birth time plus lifetime gives death time, so allocating objects of
|
||||
similar size sequentially from the same pool instance should result in
|
||||
objects allocated close to each other dying at about the same time.
|
||||
|
||||
An application that has several classes of objects of widely differing
|
||||
life expectancy will best be served by creating a different MVT pool
|
||||
instance for each life-expectancy class. A more sophisticated policy
|
||||
can use either the programmer's knowledge of the expected lifetime of
|
||||
an objector any characteristic of objects that correlates with
|
||||
lifetime to choose an appropriate pool instance to allocate in.
|
||||
|
||||
Allocating objects with unknown or very different deathtimes together
|
||||
will pessimize the space performance of MVT.
|
||||
|
||||
|
||||
A simple policy can be implemented to take advantage of MVT: Object size is typically well-correlated with object life-expectancy, and birthtime plus lifetime gives deathtime, so allocating objects of similar size sequentially from the same pool instance should result in objects allocated close to each other dying at about the same time.
|
||||
.. index::
|
||||
single: MVT; properties
|
||||
|
||||
An application that has several classes of objects of widely differing life expectancy will best be served by creating a different MVT pool instance for each life-expectancy class. A more sophisticated policy can use either the programmer's knowledge of the expected lifetime of an objector any characteristic of objects that correlates with lifetime to choose an appropriate pool instance to allocate in.
|
||||
MVT properties
|
||||
--------------
|
||||
|
||||
Allocating objects with unknown or very different deathtimes together will pessimize the space performance of MVT.
|
||||
* Does not support allocation via :c:func:`mps_alloc`.
|
||||
|
||||
::
|
||||
* Supports allocation via :term:`allocation points` only.
|
||||
|
||||
if(mps_pool_create(&pool, arena, mps_class_mvt(), 8, 32, 256, 70, 20)
|
||||
!= MPS_RES_OK)
|
||||
{
|
||||
printf("Error creating pool!");
|
||||
exit(2);
|
||||
}
|
||||
* Supports deallocation via :c:func:`mps_free`.
|
||||
|
||||
* Supports :term:`allocation frames` but does not use them to improve
|
||||
the efficiency of stack-like allocation.
|
||||
|
||||
* Does not support :term:`segregated allocation caches`.
|
||||
|
||||
* There are no garbage collections in this pool.
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is not configurable (it is the
|
||||
natural :term:`word` size of the platform).
|
||||
|
||||
* Blocks do not have :term:`dependent objects`.
|
||||
|
||||
* Blocks are not automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are not :term:`scanned <scan>`.
|
||||
|
||||
* Blocks are not protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks do not :term:`move <moving garbage collector>`.
|
||||
|
||||
* Blocks may not be registered for :term:`finalization`.
|
||||
|
||||
* Blocks must not belong to an :term:`object format`.
|
||||
|
||||
|
||||
Reserve depth
|
||||
.. index::
|
||||
single: MVT; interface
|
||||
|
||||
If a pool has a stable population, or one which only grows over
|
||||
the lifetime of the pool, or one which grows steadily and then
|
||||
shrinks steadily, use a reserve depth of 0.
|
||||
|
||||
It is always safe to use a reserve depth of 0, but if the
|
||||
population typically fluctuates in a range (for example, the
|
||||
client program repeatedly creates and destroys a subset of blocks
|
||||
in a loop), it is more efficient for the pool to retain enough
|
||||
storage to satisfy that fluctuation. For example, if a pool has an
|
||||
object population that typically fluctuates between 8,000 and
|
||||
10,000, use a reserve depth of 2,000.
|
||||
|
||||
The reserve will not normally be available to other pools for
|
||||
allocation, even when it is not used by the pool. If this is
|
||||
undesirable, a reserve depth of 0 may be used for a pool whose
|
||||
object population does vary, at a slight cost in efficiency. The
|
||||
reserve does not guarantee any particular amount of allocation.
|
||||
|
||||
Fragmentation limit
|
||||
|
||||
A fragmentation limit of 100 will cause the pool to use temporal
|
||||
fit (unless resources are exhausted). If the objects allocated in
|
||||
the pool have similar lifetime expectancies, this mode will have
|
||||
the best time- and space-efficiency. If the objects have widely
|
||||
varying lifetime expectancies,this mode will be time-efficient,
|
||||
but may be space-inefficient. An intermediate setting can be used
|
||||
to limit the space-inefficiency of temporal fit due to varying
|
||||
object life expectancies.
|
||||
|
||||
Allocation
|
||||
|
||||
The MVT pool class only supports allocation through allocation
|
||||
points. See :c:func:`mps_ap_create`.
|
||||
|
||||
|
||||
Deallocation
|
||||
|
||||
The MVT pool class supports explicit freeing. See :c:func:`mps_pool_free`.
|
||||
|
||||
|
||||
Internal Notes
|
||||
|
||||
Need a life-expectancy parameter! How else will different instances choose their Loci?
|
||||
|
||||
Need an alignment parameter. Perhaps this is embedded in a format parameter (when all pools have at least a null format).
|
||||
|
||||
It is conceivable that a client would want to mix manual and automatic pools with the manual pool being able to be a root for the automatic. To do so, MVT would need to support formatted objects and scanning. This may be added someday.
|
||||
|
||||
Eventually the MM product will include profiling tools that will help determine object characteristics that correlate with object lifetime and suggest how to configure the appropriate number of MVT pool instances and what characteristics to dispatch on when choosing which instance to allocate from.
|
||||
|
||||
[From mail.ptw.1998-08-19.02-33(0) ]
|
||||
|
||||
Remember Wilson's statement that the goal of a memory manager is to exploit the regularities in allocation patterns? My intent in the interface parameters is to accept measurable regularities in object populations, then the implementation can exploit them.
|
||||
|
||||
Perhaps the pool should accept some description of the mean and deviation of the object sizes, object population, and object lifetimes. Is that what you are getting at? [Reserve_depth is in some sense a deviation.]
|
||||
|
||||
|
||||
|
||||
--------------------
|
||||
MVT symbol reference
|
||||
--------------------
|
||||
MVT interface
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscmv2.h"
|
||||
|
||||
|
||||
.. c:function:: mps_class_t mps_class_mvt(void)
|
||||
|
||||
Return the :term:`pool class` for an MVT (Manual Variable
|
||||
|
|
@ -128,10 +130,28 @@ MVT symbol reference
|
|||
|
||||
``reserve_depth`` is the expected hysteresis of the population of
|
||||
the pool. When blocks are freed, the pool will retain sufficient
|
||||
storage to allocate ``reserve_depth`` blocks of ``mean_size`` for near
|
||||
term allocations (rather than immediately making that storage
|
||||
storage to allocate ``reserve_depth`` blocks of ``mean_size`` for
|
||||
near term allocations (rather than immediately making that storage
|
||||
available to other pools).
|
||||
|
||||
If a pool has a stable population, or one which only grows over
|
||||
the lifetime of the pool, or one which grows steadily and then
|
||||
shrinks steadily, use a reserve depth of 0.
|
||||
|
||||
It is always safe to use a reserve depth of 0, but if the
|
||||
population typically fluctuates in a range (for example, the
|
||||
client program repeatedly creates and destroys a subset of blocks
|
||||
in a loop), it is more efficient for the pool to retain enough
|
||||
storage to satisfy that fluctuation. For example, if a pool has an
|
||||
object population that typically fluctuates between 8,000 and
|
||||
10,000, use a reserve depth of 2,000.
|
||||
|
||||
The reserve will not normally be available to other pools for
|
||||
allocation, even when it is not used by the pool. If this is
|
||||
undesirable, a reserve depth of 0 may be used for a pool whose
|
||||
object population does vary, at a slight cost in efficiency. The
|
||||
reserve does not guarantee any particular amount of allocation.
|
||||
|
||||
``fragmentation_limit`` is a percentage in (0, 100] that can be used
|
||||
to set an upper limit on the space overhead of MVT in case block
|
||||
death times and allocations do not correlate well. If the free
|
||||
|
|
@ -140,12 +160,42 @@ MVT symbol reference
|
|||
first fit allocation policy, exploiting space more efficiently at
|
||||
a cost in time efficiency. A fragmentation limit of 0 would cause
|
||||
the pool to operate as a first-fit pool, at a significant cost in
|
||||
time efficiency, therefore is not permitted.
|
||||
time efficiency: therefore this is not permitted.
|
||||
|
||||
A fragmentation limit of 100 will cause the pool to use temporal
|
||||
fit (unless resources are exhausted). If the objects allocated in
|
||||
the pool have similar lifetime expectancies, this mode will have
|
||||
the best time- and space-efficiency. If the objects have widely
|
||||
varying lifetime expectancies, this mode will be time-efficient,
|
||||
but may be space-inefficient. An intermediate setting can be used
|
||||
to limit the space-inefficiency of temporal fit due to varying
|
||||
object life expectancies.
|
||||
|
||||
|
||||
------------
|
||||
Undocumented
|
||||
------------
|
||||
.. index::
|
||||
pair: MVT; introspection
|
||||
|
||||
MVT introspection
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
#include "mpscmv2.h"
|
||||
|
||||
.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool)
|
||||
|
||||
Return the total amount of free space in an MVT pool.
|
||||
|
||||
``pool`` is the MVT pool.
|
||||
|
||||
Returns the total free space in the pool, in :term:`bytes (1)`.
|
||||
|
||||
|
||||
.. c:function:: size_t mps_mvt_size(mps_pool_t pool)
|
||||
|
||||
Return the total size of an MVT pool.
|
||||
|
||||
``pool`` is the MVT pool.
|
||||
|
||||
Returns the total size of the pool, in :term:`bytes (1)`. This
|
||||
is the sum of allocated space and free space.
|
||||
|
|
|
|||
|
|
@ -2,29 +2,82 @@
|
|||
|
||||
`<https://info.ravenbrook.com/project/mps/doc/2002-06-18/obsolete-mminfo/mmdoc/doc/mps/guide/stack-alloc/>`_
|
||||
|
||||
.. index::
|
||||
single: SNC; introduction
|
||||
single: pool class; SNC
|
||||
|
||||
.. _pool-snc:
|
||||
|
||||
====================
|
||||
SNC (Stack No Check)
|
||||
====================
|
||||
|
||||
An SNC pool is scannable, in that objects may contain references to objects in other pools that will keep those objects alive (depending on rank). In this sense, an SNC pool is a de-facto root.
|
||||
**SNC** is a :term:`manually managed <manual memory management>`
|
||||
:term:`pool class` that supports a stack-like protocol for allocation
|
||||
and deallocation using :term:`allocation frames` on :term:`allocation
|
||||
points`. See :ref:`topic-frame`.
|
||||
|
||||
Exact references may point to (the start of) objects in an SNC pool, but will have no effect on whether those objects are either scanned or kept alive.
|
||||
If :c:func:`mps_ap_frame_pop` is used on an allocation point in an SNC
|
||||
pool (after a corresponding call to :c:func:`mps_ap_frame_push`), then
|
||||
the objects affected by the pop are effectively declared dead, and may
|
||||
be reclaimed by the collector. Extant references to such objects from
|
||||
reachable or *de facto* alive objects are safe, but such other objects
|
||||
should be dead; that is, such references must never be used.
|
||||
|
||||
If :c:func:`mps_ap_frame_pop` is used on an allocation point in an SNC pool (after a corresponding call to :c:func:`mps_ap_frame_push`), then the objects affected by the pop are effectively declared dead, and may be reclaimed by the collector. Extant references to such objects from reachable or de facto alive objects are safe, but such other objects should be dead; that is, such references must never be used.
|
||||
|
||||
If an allocation point is created in an SNC pool, then the call to :c:func:`mps_ap_create` will take as an additional parameter the rank (of type :c:func:`mps_rank_t`) of references in the objects to be created in that allocation point. Currently, only rank exact (:c:func:`mps_rank_exact`) is supported.
|
||||
.. index::
|
||||
single: SNC; properties
|
||||
|
||||
Objects in an SNC pool may not be registered for finalization.
|
||||
SNC properties
|
||||
--------------
|
||||
|
||||
Objects in an SNC pool will not move.
|
||||
* Does not support allocation via :c:func:`mps_alloc`.
|
||||
|
||||
* Supports allocation via :term:`allocation points` only.
|
||||
|
||||
* Does not support deallocation via :c:func:`mps_free`.
|
||||
|
||||
* Supports :term:`allocation frames`.
|
||||
|
||||
* Does not support :term:`segregated allocation caches`.
|
||||
|
||||
* Blocks may contain :term:`exact references` to blocks in the same or
|
||||
other pools (but may not contain :term:`ambiguous references` or
|
||||
:term:`weak references (1)`, and may not use :term:`remote
|
||||
references`).
|
||||
|
||||
* There are no garbage collections in this pool.
|
||||
|
||||
* Allocations may be variable in size.
|
||||
|
||||
* The :term:`alignment` of blocks is configurable.
|
||||
|
||||
* Blocks do not have :term:`dependent objects`.
|
||||
|
||||
* Blocks are not automatically :term:`reclaimed`.
|
||||
|
||||
* Blocks are :term:`scanned <scan>`.
|
||||
|
||||
* Blocks may only be referenced by :term:`base pointers` (unless they
|
||||
belong to an object format of variant auto-header).
|
||||
|
||||
* Blocks are not protected by :term:`barriers (1)`.
|
||||
|
||||
* Blocks do not :term:`move <moving garbage collector>`.
|
||||
|
||||
* Blocks may not be registered for :term:`finalization`. A consequence
|
||||
of this is that the pool's :term:`object format` need not provide a
|
||||
:term:`forward method` or an :term:`is-forwarded method`.
|
||||
|
||||
* Blocks must belong to an :term:`object format`, but this may not be
|
||||
a format of variant auto-header.
|
||||
|
||||
|
||||
|
||||
--------------------
|
||||
SNC symbol reference
|
||||
--------------------
|
||||
.. index::
|
||||
single: SNC; interface
|
||||
|
||||
SNC introspection
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -47,6 +100,12 @@ SNC symbol reference
|
|||
allocated in the pool. The format should provide at least the
|
||||
methods scan, skip, and pad.
|
||||
|
||||
.. topics::
|
||||
When creating an allocation point on an SNC pool,
|
||||
:c:func:`mps_ap_create` takes one extra argument::
|
||||
|
||||
:ref:`pool-snc`.
|
||||
mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
|
||||
mps_rank_t rank)
|
||||
|
||||
``rank`` specifies the :term:`rank` of references in objects
|
||||
allocated on this allocation point. It must be
|
||||
:c:func:`mps_rank_exact`.
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ Outstanding
|
|||
Compare the performance with the plain ``scheme.c``. The advanced
|
||||
version better be faster!
|
||||
|
||||
76. Develop debugging examples that illustrates each of the warnings
|
||||
76. Develop debugging examples that illustrate each of the warnings
|
||||
about consistency. Also to demonstrate the "garbage collect
|
||||
frequently to expose errors as soon as possible" advice.
|
||||
|
||||
|
|
@ -86,6 +86,27 @@ Outstanding
|
|||
left out?
|
||||
|
||||
133. What's the purpose of ``mps_SEH_filter`` and ``mps_SEH_handler``?
|
||||
Do they need to be documented?
|
||||
|
||||
134. What's the use case for AMS? It's suitable when you have blocks
|
||||
that need to be automatically managed but can't be moved. But
|
||||
when does this happen? If foreign code maintains remembers their
|
||||
location then it seems unlikely that they can be automatically
|
||||
managed (how can these foreign references keep the blocks
|
||||
alive?).
|
||||
|
||||
135. Does AMS use protection? I see that it calls ``ShieldExpose`` and
|
||||
``ShieldCover`` when calling the format's skip method, but not
|
||||
otherwise (e.g. when calling the format's scan method). If it
|
||||
does I need to update the pool choice algorithm.
|
||||
|
||||
Similar question for SNC? It calls ``ShieldExpose`` and
|
||||
``ShieldCover`` when calling the format's pad method, but not
|
||||
otherwise.
|
||||
|
||||
136. It seems possible that MV should not be used. What should I say
|
||||
about this? Should we remove MV from the documentation
|
||||
altogether.
|
||||
|
||||
|
||||
Complete
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ pools).
|
|||
Allocation frames can be used by the :term:`client program` to
|
||||
efficiently implement stack-like patterns of allocation.
|
||||
|
||||
.. note::
|
||||
|
||||
All :term:`pool classes` that support :term:`allocation points`
|
||||
also support pushing and popping of allocation frames, but only
|
||||
the :ref:`pool-snc` pool class actually uses these frames to
|
||||
manage its blocks.
|
||||
|
||||
|
||||
.. c:type:: mps_frame_t
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue