diff options
Diffstat (limited to 'system/doc/efficiency_guide/processes.xml')
-rw-r--r-- | system/doc/efficiency_guide/processes.xml | 159 |
1 files changed, 82 insertions, 77 deletions
diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml index 86951e2dcc..3bdc314235 100644 --- a/system/doc/efficiency_guide/processes.xml +++ b/system/doc/efficiency_guide/processes.xml @@ -30,15 +30,15 @@ </header> <section> - <title>Creation of an Erlang process</title> + <title>Creating an Erlang Process</title> - <p>An Erlang process is lightweight compared to operating - systems threads and processes.</p> + <p>An Erlang process is lightweight compared to threads and + processes in operating systems.</p> <p>A newly spawned Erlang process uses 309 words of memory in the non-SMP emulator without HiPE support. (SMP support - and HiPE support will both add to this size.) The size can - be found out like this:</p> + and HiPE support both add to this size.) The size can + be found as follows:</p> <pre> Erlang (BEAM) emulator version 5.6 [async-threads:0] [kernel-poll:false] @@ -51,11 +51,11 @@ Eshell V5.6 (abort with ^G) 3> <input>Bytes div erlang:system_info(wordsize).</input> 309</pre> - <p>The size includes 233 words for the heap area (which includes the stack). - The garbage collector will increase the heap as needed.</p> + <p>The size includes 233 words for the heap area (which includes the + stack). The garbage collector increases the heap as needed.</p> <p>The main (outer) loop for a process <em>must</em> be tail-recursive. - If not, the stack will grow until the process terminates.</p> + Otherwise, the stack grows until the process terminates.</p> <p><em>DO NOT</em></p> <code type="erl"> @@ -74,7 +74,7 @@ loop() -> <p>The call to <c>io:format/2</c> will never be executed, but a return address will still be pushed to the stack each time <c>loop/0</c> is called recursively. The correct tail-recursive - version of the function looks like this:</p> + version of the function looks as follows:</p> <p><em>DO</em></p> <code type="erl"> @@ -90,92 +90,98 @@ loop() -> end.</code> <section> - <title>Initial heap size</title> + <title>Initial Heap Size</title> <p>The default initial heap size of 233 words is quite conservative - in order to support Erlang systems with hundreds of thousands or - even millions of processes. The garbage collector will grow and - shrink the heap as needed.</p> + to support Erlang systems with hundreds of thousands or + even millions of processes. The garbage collector grows and + shrinks the heap as needed.</p> <p>In a system that use comparatively few processes, performance - <em>might</em> be improved by increasing the minimum heap size using either - the <c>+h</c> option for + <em>might</em> be improved by increasing the minimum heap size + using either the <c>+h</c> option for <seealso marker="erts:erl">erl</seealso> or on a process-per-process basis using the <c>min_heap_size</c> option for <seealso marker="erts:erlang#spawn_opt/4">spawn_opt/4</seealso>.</p> - <p>The gain is twofold: Firstly, although the garbage collector will - grow the heap, it will grow it step by step, which will be more - costly than directly establishing a larger heap when the process - is spawned. Secondly, the garbage collector may also shrink the - heap if it is much larger than the amount of data stored on it; - setting the minimum heap size will prevent that.</p> - - <warning><p>The emulator will probably use more memory, and because garbage - collections occur less frequently, huge binaries could be + <p>The gain is twofold:</p> + <list type="bulleted"> + <item>Although the garbage collector grows the heap, it grows it + step-by-step, which is more costly than directly establishing a + larger heap when the process is spawned.</item> + <item>The garbage collector can also shrink the heap if it is + much larger than the amount of data stored on it; + setting the minimum heap size prevents that.</item> + </list> + + <warning><p>The emulator probably uses more memory, and because garbage + collections occur less frequently, huge binaries can be kept much longer.</p></warning> <p>In systems with many processes, computation tasks that run - for a short time could be spawned off into a new process with - a higher minimum heap size. When the process is done, it will - send the result of the computation to another process and terminate. - If the minimum heap size is calculated properly, the process may not - have to do any garbage collections at all. - <em>This optimization should not be attempted + for a short time can be spawned off into a new process with + a higher minimum heap size. When the process is done, it sends + the result of the computation to another process and terminates. + If the minimum heap size is calculated properly, the process might + not have to do any garbage collections at all. + <em>This optimization is not to be attempted without proper measurements.</em></p> </section> - </section> <section> - <title>Process messages</title> + <title>Process Messages</title> - <p>All data in messages between Erlang processes is copied, with - the exception of + <p>All data in messages between Erlang processes is copied, + except for <seealso marker="binaryhandling#refc_binary">refc binaries</seealso> on the same Erlang node.</p> <p>When a message is sent to a process on another Erlang node, - it will first be encoded to the Erlang External Format before - being sent via an TCP/IP socket. The receiving Erlang node decodes - the message and distributes it to the right process.</p> + it is first encoded to the Erlang External Format before + being sent through a TCP/IP socket. The receiving Erlang node decodes + the message and distributes it to the correct process.</p> <section> - <title>The constant pool</title> + <title>Constant Pool</title> <p>Constant Erlang terms (also called <em>literals</em>) are now kept in constant pools; each loaded module has its own pool. - The following function</p> + The following function does no longer build the tuple every time + it is called (only to have it discarded the next time the garbage + collector was run), but the tuple is located in the module's + constant pool:</p> <p><em>DO</em> (in R12B and later)</p> <code type="erl"> days_in_month(M) -> - element(M, {31,28,31,30,31,30,31,31,30,31,30,31}).</code> - - <p>will no longer build the tuple every time it is called (only - to have it discarded the next time the garbage collector was run), but - the tuple will be located in the module's constant pool.</p> + element(M, {31,28,31,30,31,30,31,31,30,31,30,31}).</code> <p>But if a constant is sent to another process (or stored in - an ETS table), it will be <em>copied</em>. - The reason is that the run-time system must be able - to keep track of all references to constants in order to properly - unload code containing constants. (When the code is unloaded, - the constants will be copied to the heap of the processes that refer + an Ets table), it is <em>copied</em>. + The reason is that the runtime system must be able + to keep track of all references to constants to unload code + containing constants properly. (When the code is unloaded, + the constants are copied to the heap of the processes that refer to them.) The copying of constants might be eliminated in a future - release.</p> + Erlang/OTP release.</p> </section> <section> - <title>Loss of sharing</title> + <title>Loss of Sharing</title> - <p>Shared sub-terms are <em>not</em> preserved when a term is sent - to another process, passed as the initial process arguments in - the <c>spawn</c> call, or stored in an ETS table. - That is an optimization. Most applications do not send messages - with shared sub-terms.</p> + <p>Shared subterms are <em>not</em> preserved in the following + cases:</p> + <list type="bulleted"> + <item>When a term is sent to another process</item> + <item>When a term is passed as the initial process arguments in + the <c>spawn</c> call</item> + <item>When a term is stored in an Ets table</item> + </list> + <p>That is an optimization. Most applications do not send messages + with shared subterms.</p> - <p>Here is an example of how a shared sub-term can be created:</p> + <p>The following example shows how a shared subterm can be created:</p> <code type="erl"> kilo_byte() -> @@ -186,32 +192,32 @@ kilo_byte(0, Acc) -> kilo_byte(N, Acc) -> kilo_byte(N-1, [Acc|Acc]).</code> - <p><c>kilo_byte/0</c> creates a deep list. If we call - <c>list_to_binary/1</c>, we can convert the deep list to a binary - of 1024 bytes:</p> + <p><c>kilo_byte/1</c> creates a deep list. + If <c>list_to_binary/1</c> is called, the deep list can be + converted to a binary of 1024 bytes:</p> <pre> 1> <input>byte_size(list_to_binary(efficiency_guide:kilo_byte())).</input> 1024</pre> - <p>Using the <c>erts_debug:size/1</c> BIF we can see that the + <p>Using the <c>erts_debug:size/1</c> BIF, it can be seen that the deep list only requires 22 words of heap space:</p> <pre> 2> <input>erts_debug:size(efficiency_guide:kilo_byte()).</input> 22</pre> - <p>Using the <c>erts_debug:flat_size/1</c> BIF, we can calculate - the size of the deep list if sharing is ignored. It will be + <p>Using the <c>erts_debug:flat_size/1</c> BIF, the size of the + deep list can be calculated if sharing is ignored. It becomes the size of the list when it has been sent to another process - or stored in an ETS table:</p> + or stored in an Ets table:</p> <pre> 3> <input>erts_debug:flat_size(efficiency_guide:kilo_byte()).</input> 4094</pre> - <p>We can verify that sharing will be lost if we insert the - data into an ETS table:</p> + <p>It can be verified that sharing will be lost if the data is + inserted into an Ets table:</p> <pre> 4> <input>T = ets:new(tab, []).</input> @@ -223,21 +229,21 @@ true 7> <input>erts_debug:flat_size(element(2, hd(ets:lookup(T, key)))).</input> 4094</pre> - <p>When the data has passed through an ETS table, + <p>When the data has passed through an Ets table, <c>erts_debug:size/1</c> and <c>erts_debug:flat_size/1</c> return the same value. Sharing has been lost.</p> - <p>In a future release of Erlang/OTP, we might implement a - way to (optionally) preserve sharing. We have no plans to make - preserving of sharing the default behaviour, since that would + <p>In a future Erlang/OTP release, it might be implemented a + way to (optionally) preserve sharing. There are no plans to make + preserving of sharing the default behaviour, as that would penalize the vast majority of Erlang applications.</p> </section> </section> <section> - <title>The SMP emulator</title> + <title>SMP Emulator</title> - <p>The SMP emulator (introduced in R11B) will take advantage of a + <p>The SMP emulator (introduced in R11B) takes advantage of a multi-core or multi-CPU computer by running several Erlang scheduler threads (typically, the same as the number of cores). Each scheduler thread schedules Erlang processes in the same way as the Erlang scheduler @@ -247,11 +253,11 @@ true <em>must have more than one runnable Erlang process</em> most of the time. Otherwise, the Erlang emulator can still only run one Erlang process at the time, but you must still pay the overhead for locking. Although - we try to reduce the locking overhead as much as possible, it will never - become exactly zero.</p> + Erlang/OTP tries to reduce the locking overhead as much as possible, + it will never become exactly zero.</p> - <p>Benchmarks that may seem to be concurrent are often sequential. - The estone benchmark, for instance, is entirely sequential. So is also + <p>Benchmarks that appear to be concurrent are often sequential. + The estone benchmark, for example, is entirely sequential. So is the most common implementation of the "ring benchmark"; usually one process is active, while the others wait in a <c>receive</c> statement.</p> @@ -259,6 +265,5 @@ true can be used to profile your application to see how much potential (or lack thereof) it has for concurrency.</p> </section> - </chapter> |