|
| JMemoryManager () |
|
void | Receive (JBroadcaster *sender, const Message &message) override |
|
void | HandleObjectDeletedAsArray (const JMMRecord &record) |
|
void | HandleArrayDeletedAsObject (const JMMRecord &record) |
|
void | HandleUnallocatedDeletion (const JUtf8Byte *file, const JUInt32 line, const bool isArray) |
|
void | HandleMultipleDeletion (const JMMRecord &thisRecord, const JUtf8Byte *file, const JUInt32 line, const bool isArray) |
|
void | HandleMultipleAllocation (const JMMRecord &thisRecord, const JMMRecord &firstRecord) |
|
| JBroadcaster (const JBroadcaster &source) |
|
void | ListenTo (const JBroadcaster *sender) |
|
void | StopListening (const JBroadcaster *sender) |
|
void | ClearWhenGoingAway (const JBroadcaster *sender, void *pointerToMember) |
|
void | StopListening (const JBroadcaster *sender, const std::type_info &messageType) |
|
template<class T > |
void | Send (JBroadcaster *recipient, const T &message) |
|
template<class T > |
void | Broadcast (const T &message) |
|
void | SendWithFeedback (JBroadcaster *recipient, Message *message) |
|
void | BroadcastWithFeedback (Message *message) |
|
virtual void | ReceiveWithFeedback (JBroadcaster *sender, Message *message) |
|
virtual void | ReceiveGoingAway (JBroadcaster *sender) |
|
JMemoryManager controls all memory allocation in a JCore/JX program,
normally through the JCore operator jnew and jdelete replacements. It is
a singleton class (it can only be instantiated once) so that memory
allocation is consistent throughout a single program. The unique
instance is accessed through the static member function Instance.
JMemoryManager and the JCore operator jnew present a paradox: like all
JX objects created at run time, JMemoryManager components are allocated
with the global operator jnew. However, operator jnew uses
JMemoryManager to determine what its behavior should be; thus
JMemoryManager must exist before it is allocated! It is not necessary
for JMemoryManager to have its own class operator jnew and jdelete to
solve this problem; JMemoryManager uses static buffering to allow
recursive calls to jnew and jdelete, and this also works when the
manager itself is created.
Most programs will interact with the memory manager indirectly through
operator jnew and jdelete and will not be aware of its existence.
However, JMemoryManager can supply a number of services for programs
which take the trouble to interact with it directly. Currently this
ability is limited to requesting simple statistics reporting, but the
capabilities will expand in the future.
JMemoryManager cannot be used in conjunction with objects that define
their own versions of new and delete.
JMemoryManager's consistency checks depend on it controlling every jnew
and jdelete, so that if it is to record information it must begin doing
so at the moment of construction. Because the memory manager is almost
certain to be created before execution of main even begins (any static
object whose constructor calls operator jnew will guarantee this on any
system, for example), the memory manager uses lots of environment
variables to control its operation (for all variables case is
irrelevant):
JMM_TABLE_TYPE If this environment variable is set to "array"
(case is irrelevant) the manager uses a stack
implementation for its memory block table, and
if its value is "hashtable" a hash table
implementation is used. If it does not exist,
or its value is unrecognized, the default
(currently hashtable) is used without warning.
This is mostly useful for debugging the tables
themselves; otherwise, there is little reason
to use the grossly inefficient array
implementation.
JMM_RECORD_ALLOCATED If this environment variable is set to "yes" the
manager will keep a record of all currently
allocated memory.
CancelRecordAllocated() can stop the recording
of initializations, but once canceled it cannot
be restarted.
JMM_INITIALIZE If this environment variable is set but given no
value the manager will initialize new memory blocks
to the default AllocateGarbage value. If it is
given a numerical value, that will be the value
used for initialization. If the manager cannot
understand the value given, the default is used
(setting it to "default" is the recommended way
to do this intentionally). If it does not exist
or is set to "no" memory blocks will not be
initialized.
JMM_SHRED If this environment variable is set but given no
value the manager will set deleted blocks to the
default DeallocateGarbage value. If it is given
a numerical value, that will be the value the
blocks are set to. If the manager cannot
understand the value given, the default is used
(setting it to "default" is the recommended way
to do this intentionally). If it does not exist
or is set to "no" memory blocks will not be
initialized.
This variable is meaningless if allocation records
are not being kept, because in that case the
manager cannot know the size of the block being
freed.
Keep in mind that jdelete (via free()) generally
will store information at the beginning of each
deallocated block. This information will overwrite
the JMM garbage values at those locations, so
don't expect the first few bytes to have the
JMM_SHRED value.
Generally, you'll want to use different initialize
and shred values so you can look at a piece of
memory and see at a glance whether the manager
thinks it is allocated or deallocated.
JMM_RECORD_DEALLOCATED If this environment variable is set to "yes" the
manager will keep a record of all memory which
has been deallocated. It is useless unless
JMM_RECORD_ALLOCATED is also set. Can be canceled
by CancelRecordDeallocated.
JMM_CHECK_DOUBLE_ALLOCATION If this environment variable is set to "yes"
the manager will complain if memory is allocated at
a location previously allocated (this indicates an
error in the system malloc() and so is only useful
for debugging the C memory manager itself, or more
likely for detecting a logic error in JMM). It is
useless unless JMM_RECORD_ALLOCATED is also set.
The SetCheckDoubleAllocation method overrides this
variable.
JMM_BROADCAST_ERRORS If this environment variable is set to "yes" the
manager will broadcast when errors occur. It
is overridden by the SetBroadcastErrors method.
JMM_PRINT_EXIT_STATS If this environment variable is set to "yes" the
manager will print dynamic memory usage stats
when the program finishes. The SetPrintExitStats
method overrides the environment variable setting.
JMM_PRINT_LIBRARY_STATS If this environment variable is set to "yes"
then whenever allocation stats are printed (such as
at program exit) the manager will also print stats
on the library code. The SetPrintLibraryStats
method overrides the environment variable setting.
JMM_PRINT_INTERNAL_STATS If this environment variable is set to "yes"
then whenever allocation stats are printed (such as
at program exit) the manager will also print stats
on its internal state, such as the memory it has
allocated for its own use. The SetPrintInternalStats
method overrides the environment variable setting.
JMM_ABORT_UNKNOWN_ALLOC If set to "yes", the process will abort if memory
is allocated by code that the memory manager cannot
locate. One reason to do this is to examine the
resulting core dump for the location of the offending
JMM_NO_PRINT_ERRORS Setting this environment variable to "yes" suppresses
all printing (the default is to print because
JMemoryManager's messages are already off by default
and if you turn them on you likely want to print error
messages).
JMM_PIPE UNIX pipe on which to receive requests. Also used
to send exit stats.
MALLOC_PERTURB_ Setting this environment variable turns on
initialization and shredding of memory in libc.
(JMM_NO_PRINT_ERRORS is actually read in the JMMErrorPrinter proxy object.)
Setting up so many variables can be a pain, and frequently writing a
few handy shell scripts is the best solution. After you do this you'll
forget exactly what the variables do when you go to change them! The
descriptions are commented out with the unix script comment symbol,
'#', to make it easy to paste them directly into a shell script;
self-documentation is much easier than having to find this file again
to modify the script. The jmmenv script provides an example of this as
well as a handy summary of all the variables and their effects.
To get file/line information you must include <jNew.h>, because it must
define jnew and jdelete. The recommended way to do this is to #include
jAssert.h, since it #include's jNew.h.
Performance:
A test involving starting and immediately quitting jcc on a project
that displays the jcore+jx inheritance tree with various JMM
environment settings produced the following results (in CPU seconds):
baseline: 1.97
+init: 2.05
+hash: 3.99
+broadcast: 4.05
+shred: 3.94
+dealloc: 6.32
+double alloc: 6.54
+array-dealloc: 616.77
+dealloc: 611.67
Repeated runs showed the accuracy was no better than a few percent.
This suggests that there is no noticable penalty for initialization or
shredding. Clearly hash tables were at least two orders of magnitude
better than arrays. For building the tree, deallocation didn't cost much
extra with arrays, though if the program would have kept running it
eventually would have.
Base code generated by Codemill v0.1.0