persistent_term(3erl) Erlang Module Definition persistent_term(3erl)
NAME
persistent_term - Persistent terms.
DESCRIPTION
This module is similar to ets in that it provides a storage for Erlang
terms that can be accessed in constant time, but with the difference
that persistent_term has been highly optimized for reading terms at the
expense of writing and updating terms. When a persistent term is up-
dated or deleted, a global garbage collection pass is run to scan all
processes for the deleted term, and to copy it into each process that
still uses it. Therefore, persistent_term is suitable for storing Er-
lang terms that are frequently accessed but never or infrequently up-
dated.
Warning:
Persistent terms is an advanced feature and is not a general replace-
ment for ETS tables. Before using persistent terms, make sure to fully
understand the consequence to system performance when updating or
deleting persistent terms.
Term lookup (using get/1), is done in constant time and without taking
any locks, and the term is not copied to the heap (as is the case with
terms stored in ETS tables).
Storing or updating a term (using put/2) is proportional to the number
of already created persistent terms because the hash table holding the
keys will be copied. In addition, the term itself will be copied.
When a (complex) term is deleted (using erase/1) or replaced by another
(using put/2), a global garbage collection is initiated. It works like
this:
* All processes in the system will be scheduled to run a scan of
their heaps for the term that has been deleted. While such scan is
relatively light-weight, if there are many processes, the system
can become less responsive until all process have scanned their
heaps.
* If the deleted term (or any part of it) is still used by a process,
that process will do a major (fullsweep) garbage collection and
copy the term into the process. However, at most two processes at a
time will be scheduled to do that kind of garbage collection.
Deletion of atoms and other terms that fit in one machine word is spe-
cially optimized to avoid doing a global GC. It is still not recom-
mended to update persistent terms with such values too frequently be-
cause the hash table holding the keys is copied every time a persistent
term is updated.
Some examples are suitable uses for persistent terms are:
* Storing of configuration data that must be easily accessible by all
processes.
* Storing of references for NIF resources.
* Storing of references for efficient counters.
* Storing an atom to indicate a logging level or whether debugging is
turned on.
STORING HUGE PERSISTENT TERMS
The current implementation of persistent terms uses the literal alloca-
tor also used for literals (constant terms) in BEAM code. By default, 1
GB of virtual address space is reserved for literals in BEAM code and
persistent terms. The amount of virtual address space reserved for lit-
erals can be changed by using the +MIscs option when starting the emu-
lator.
Here is an example how the reserved virtual address space for literals
can be raised to 2 GB (2048 MB):
erl +MIscs 2048
BEST PRACTICES FOR USING PERSISTENT TERMS
It is recommended to use keys like ?MODULE or {?MODULE,SubKey} to avoid
name collisions.
Prefer creating a few large persistent terms to creating many small
persistent terms. The execution time for storing a persistent term is
proportional to the number of already existing terms.
Updating a persistent term with the same value as it already has is
specially optimized to do nothing quickly; thus, there is no need com-
pare the old and new values and avoid calling put/2 if the values are
equal.
When atoms or other terms that fit in one machine word are deleted, no
global GC is needed. Therefore, persistent terms that have atoms as
their values can be updated more frequently, but note that updating
such persistent terms is still much more expensive than reading them.
Updating or deleting a persistent term will trigger a global GC if the
term does not fit in one machine word. Processes will be scheduled as
usual, but all processes will be made runnable at once, which will make
the system less responsive until all process have run and scanned their
heaps for the deleted terms. One way to minimize the effects on respon-
siveness could be to minimize the number of processes on the node be-
fore updating or deleting a persistent term. It would also be wise to
avoid updating terms when the system is at peak load.
Avoid storing a retrieved persistent term in a process if that persis-
tent term could be deleted or updated in the future. If a process holds
a reference to a persistent term when the term is deleted, the process
will be garbage collected and the term copied to process.
Avoid updating or deleting more than one persistent term at a time.
Each deleted term will trigger its own global GC. That means that
deleting N terms will make the system less responsive N times longer
than deleting a single persistent term. Therefore, terms that are to be
updated at the same time should be collected into a larger term, for
example, a map or a tuple.
EXAMPLE
The following example shows how lock contention for ETS tables can be
minimized by having one ETS table for each scheduler. The table identi-
fiers for the ETS tables are stored as a single persistent term:
%% There is one ETS table for each scheduler.
Sid = erlang:system_info(scheduler_id),
Tid = element(Sid, persistent_term:get(?MODULE)),
ets:update_counter(Tid, Key, 1).
DATA TYPES
key() = term()
Any Erlang term.
value() = term()
Any Erlang term.
EXPORTS
erase(Key) -> Result
Types:
Key = key()
Result = boolean()
Erase the name for the persistent term with key Key. The return
value will be true if there was a persistent term with the key
Key, and false if there was no persistent term associated with
the key.
If there existed a previous persistent term associated with key
Key, a global GC has been initiated when erase/1 returns. See
Description.
get() -> List
Types:
List = [{key(), value()}]
Retrieve the keys and values for all persistent terms. The keys
will be copied to the heap for the process calling get/0, but
the values will not.
get(Key) -> Value
Types:
Key = key()
Value = value()
Retrieve the value for the persistent term associated with the
key Key. The lookup will be made in constant time and the value
will not be copied to the heap of the calling process.
This function fails with a badarg exception if no term has been
stored with the key Key.
If the calling process holds on to the value of the persistent
term and the persistent term is deleted in the future, the term
will be copied to the process.
get(Key, Default) -> Value
Types:
Key = key()
Default = Value = value()
Retrieve the value for the persistent term associated with the
key Key. The lookup will be made in constant time and the value
will not be copied to the heap of the calling process.
This function returns Default if no term has been stored with
the key Key.
If the calling process holds on to the value of the persistent
term and the persistent term is deleted in the future, the term
will be copied to the process.
info() -> Info
Types:
Info = #{count := Count, memory := Memory}
Count = Memory = integer() >= 0
Return information about persistent terms in a map. The map has
the following keys:
count:
The number of persistent terms.
memory:
The total amount of memory (measured in bytes) used by all
persistent terms.
put(Key, Value) -> ok
Types:
Key = key()
Value = value()
Store the value Value as a persistent term and associate it with
the key Key.
If the value Value is equal to the value previously stored for
the key, put/2 will do nothing and return quickly.
If there existed a previous persistent term associated with key
Key, a global GC has been initiated when put/2 returns. See De-
scription.
Ericsson AB erts 11.0.2 persistent_term(3erl)