diff options
-rw-r--r-- | changelog.md | 5 | ||||
-rw-r--r-- | compiler/commands.nim | 4 | ||||
-rw-r--r-- | doc/advopt.txt | 7 | ||||
-rw-r--r-- | doc/backends.rst | 38 | ||||
-rw-r--r-- | doc/destructors.rst | 12 | ||||
-rw-r--r-- | doc/docs.rst | 4 | ||||
-rw-r--r-- | doc/mm.rst | 95 | ||||
-rw-r--r-- | doc/nimc.rst | 22 | ||||
-rw-r--r-- | doc/refc.rst (renamed from doc/gc.rst) | 109 | ||||
-rw-r--r-- | koch.nim | 2 | ||||
-rw-r--r-- | tools/kochdocs.nim | 2 |
11 files changed, 157 insertions, 143 deletions
diff --git a/changelog.md b/changelog.md index 63c3eff40..258cf73e4 100644 --- a/changelog.md +++ b/changelog.md @@ -53,7 +53,7 @@ Baz = object ``` - [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental, - meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. + meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. ## Compiler changes @@ -63,5 +63,6 @@ ## Tool changes - +- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the + reality better. (Nim moved away from all techniques based on "tracing".) diff --git a/compiler/commands.nim b/compiler/commands.nim index a8caad916..d5c5f24e4 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -248,7 +248,7 @@ template deprecatedAlias(oldName, newName: string) = proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool = case switch.normalize - of "gc": + of "gc", "mm": case arg.normalize of "boehm": result = conf.selectedGC == gcBoehm of "refc": result = conf.selectedGC == gcRefc @@ -596,7 +596,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info) of "project": processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) - of "gc": + of "gc", "mm": if conf.backend == backendJs: return # for: bug #16033 expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: diff --git a/doc/advopt.txt b/doc/advopt.txt index 063d018d1..79e784fde 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -122,8 +122,9 @@ Advanced options: --skipUserCfg:on|off do not read the user's configuration file --skipParentCfg:on|off do not read the parent dirs' configuration files --skipProjCfg:on|off do not read the project's configuration file - --gc:refc|arc|orc|markAndSweep|boehm|go|none|regions - select the GC to use; default is 'refc' + --mm:orc|arc|refc|markAndSweep|boehm|go|none|regions + select which memory management to use; default is 'refc' + recommended is 'orc' --exceptions:setjmp|cpp|goto|quirky select the exception handling implementation --index:on|off turn index file generation on|off @@ -163,4 +164,4 @@ Advanced options: --profileVM:on|off turn compile time VM profiler on|off --sinkInference:on|off turn sink parameter inference on|off (default: on) --panics:on|off turn panics into process terminations (default: off) - --deepcopy:on|off enable 'system.deepCopy' for ``--gc:arc|orc`` + --deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc`` diff --git a/doc/backends.rst b/doc/backends.rst index 377e899b0..d55503d10 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -105,7 +105,7 @@ file. However, you can also run the code with `nodejs`:idx: If you experience errors saying that `globalThis` is not defined, be sure to run a recent version of Node.js (at least 12.0). - + Interfacing =========== @@ -387,14 +387,8 @@ A similar thing happens with C code invoking Nim code which returns a proc gimme(): cstring {.exportc.} = result = "Hey there C code! " & $rand(100) -Since Nim's garbage collector is not aware of the C code, once the +Since Nim's reference counting mechanism is not aware of the C code, once the `gimme` proc has finished it can reclaim the memory of the `cstring`. -However, from a practical standpoint, the C code invoking the `gimme` -function directly will be able to use it since Nim's garbage collector has -not had a chance to run *yet*. This gives you enough time to make a copy for -the C side of the program, as calling any further Nim procs *might* trigger -garbage collection making the previously returned string garbage. Or maybe you -are `yourself triggering the collection <gc.html>`_. Custom data types @@ -414,31 +408,3 @@ you can clean it up. And of course, once cleaned you should avoid accessing it from Nim (or C for that matter). Typically C data structures have their own `malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping these for the Nim side should be enough. - - -Thread coordination -------------------- - -When the `NimMain()` function is called Nim initializes the garbage -collector to the current thread, which is usually the main thread of your -application. If your C code later spawns a different thread and calls Nim -code, the garbage collector will fail to work properly and you will crash. - -As long as you don't use the threadvar emulation Nim uses native thread -variables, of which you get a fresh version whenever you create a thread. You -can then attach a GC to this thread via - -.. code-block:: nim - - system.setupForeignThreadGc() - -It is **not** safe to disable the garbage collector and enable it after the -call from your background thread even if the code you are calling is short -lived. - -Before the thread exits, you should tear down the thread's GC to prevent memory -leaks by calling - -.. code-block:: nim - - system.tearDownForeignThreadGc() diff --git a/doc/destructors.rst b/doc/destructors.rst index 83a50230b..c98e94536 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -43,7 +43,7 @@ written as: dealloc(x.data) proc `=trace`[T](x: var myseq[T]; env: pointer) = - # `=trace` allows the cycle collector `--gc:orc` + # `=trace` allows the cycle collector `--mm:orc` # to understand how to trace the object graph. if x.data != nil: for i in 0..<x.len: `=trace`(x.data[i], env) @@ -208,7 +208,7 @@ by the compiler. Notice that there is no `=` before the `{.error.}` pragma. `=trace` hook ------------- -A custom **container** type can support Nim's cycle collector `--gc:orc` via +A custom **container** type can support Nim's cycle collector `--mm:orc` via the `=trace` hook. If the container does not implement `=trace`, cyclic data structures which are constructed with the help of the container might leak memory or resources, but memory safety is not compromised. @@ -224,7 +224,7 @@ to calls of the built-in `=trace` operation. Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates manually allocated resources is also used, and then only when there is a chance of cyclic -references from items within the manually allocated resources when it is desired that `--gc:orc` +references from items within the manually allocated resources when it is desired that `--mm:orc` is able to break and collect these cyclic referenced resources. Currently however, there is a mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically create a version of the other which will then conflict with the creation of the second of the @@ -256,7 +256,7 @@ The general pattern in using `=destroy` with `=trace` looks like: # following may be other custom "hooks" as required... -**Note**: The `=trace` hooks (which are only used by `--gc:orc`) are currently more experimental and less refined +**Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined than the other hooks. @@ -558,10 +558,10 @@ for expressions of type `lent T` or of type `var T`. The cursor pragma ================= -Under the `--gc:arc|orc`:option: modes Nim's `ref` type is implemented +Under the `--mm:arc|orc`:option: modes Nim's `ref` type is implemented via the same runtime "hooks" and thus via reference counting. This means that cyclic structures cannot be freed -immediately (`--gc:orc`:option: ships with a cycle collector). +immediately (`--mm:orc`:option: ships with a cycle collector). With the `cursor` pragma one can break up cycles declaratively: .. code-block:: nim diff --git a/doc/docs.rst b/doc/docs.rst index b34383253..3c348fcb8 100644 --- a/doc/docs.rst +++ b/doc/docs.rst @@ -22,8 +22,8 @@ The documentation consists of several documents: - | `Tools documentation <tools.html>`_ | Description of some tools that come with the standard distribution. -- | `GC <gc.html>`_ - | Additional documentation about Nim's multi-paradigm memory management strategies +- | `Memory management <mm.html>`_ + | Additional documentation about Nim's memory management strategies | and how to operate them in a realtime setting. - | `Source code filters <filters.html>`_ diff --git a/doc/mm.rst b/doc/mm.rst new file mode 100644 index 000000000..b6941a901 --- /dev/null +++ b/doc/mm.rst @@ -0,0 +1,95 @@ +======================= +Nim's Memory Management +======================= + +.. default-role:: code +.. include:: rstcommon.rst + +:Author: Andreas Rumpf +:Version: |nimversion| + +.. + + + "The road to hell is paved with good intentions." + + +Multi-paradigm Memory Management Strategies +=========================================== + +.. default-role:: option + +Nim offers multiple different memory management strategies. +To choose the memory management strategy use the `--mm:` switch. + +**The recommended switch for newly written Nim code is `--mm:orc`.** + + +ARC/ORC +------- + +`--mm:orc` is a memory management mode primarily based on reference counting. Cycles +in the object graph are handled by a "cycle collector" which is based on "trial deletion". +Since algorithms based on "tracing" are not used, the runtime behavior is oblivious to +the involved heap sizes. + +The reference counting operations (= "RC ops") do not use atomic instructions and do not have to -- +instead entire subgraphs are *moved* between threads. The Nim compiler also aggressively +optimizes away RC ops and exploits `move semantics <destructors.html#move-semantics>`_. + +Nim performs a fair share of optimizations for ARC/ORC; you can inspect what it did +to your time critical function via `--expandArc:functionName`. + +`--mm:arc` uses the same mechanism as `--mm:orc`, but it leaves out the cycle collector. +Both ARC and ORC offer deterministic performance for `hard realtime`:idx: systems, but +ARC can be easier to reason about for people coming from Ada/C++/C -- roughly speaking +the memory for a variable is freed when it goes "out of scope". + +We generally advise you to use the `acyclic` annotation in order to optimize away the +cycle collector's overhead +but `--mm:orc` also produces more machine code than `--mm:arc`, so if you're on a target +where code size matters and you know that your code does not produce cycles, you can +use `--mm:arc`. Notice that the default `async`:idx: implementation produces cycles +and leaks memory with `--mm:arc`, in other words, for `async` you need to use `--mm:orc`. + + + +Other MM modes +-------------- + +.. note:: The default `refc` GC is incremental, thread-local and not "stop-the-world". + +--mm:refc This is the default memory management strategy. It's a + deferred reference counting based garbage collector + with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. + `This document <refc.html>`_ contains further information. +--mm:markAndSweep Simple Mark-And-Sweep based garbage collector. + Heaps are thread-local. +--mm:boehm Boehm based garbage collector, it offers a shared heap. +--mm:go Go's garbage collector, useful for interoperability with Go. + Offers a shared heap. + +--mm:none No memory management strategy nor a garbage collector. Allocated memory is + simply never freed. You should use `--mm:arc` instead. + +Here is a comparison of the different memory management modes: + +================== ======== ================= ============== =================== +Memory Management Heap Reference Cycles Stop-The-World Command line switch +================== ======== ================= ============== =================== +ORC Shared Cycle Collector No `--mm:orc` +ARC Shared Leak No `--mm:arc` +RefC Local Cycle Collector No `--mm:refc` +Mark & Sweep Local Cycle Collector No `--mm:markAndSweep` +Boehm Shared Cycle Collector Yes `--mm:boehm` +Go Shared Cycle Collector Yes `--mm:go` +None Manual Manual Manual `--mm:none` +================== ======== ================= ============== =================== + +.. default-role:: code +.. include:: rstcommon.rst + +JavaScript's garbage collector is used for the `JavaScript and NodeJS +<backends.html#backends-the-javascript-target>`_ compilation targets. +The `NimScript <nims.html>`_ target uses the memory management strategy built into +the Nim compiler. diff --git a/doc/nimc.rst b/doc/nimc.rst index 6be4c204e..eb066e748 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -408,13 +408,13 @@ to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option: and `passL`:option: command line switches to something like: .. code-block:: cmd - nim c ... --d:nimAllocPagesViaMalloc --gc:orc --passC="-I$DEVKITPRO/libnx/include" ... + nim c ... --d:nimAllocPagesViaMalloc --mm:orc --passC="-I$DEVKITPRO/libnx/include" ... --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" or setup a ``nim.cfg`` file like so:: #nim.cfg - --gc:orc + --mm:orc --d:nimAllocPagesViaMalloc --passC="-I$DEVKITPRO/libnx/include" --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" @@ -485,10 +485,10 @@ Define Effect `useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's own memory manager, albeit prefixing each allocation with its size to support clearing memory on reallocation. - This only works with `--gc:none`:option:, - `--gc:arc`:option: and `--gc:orc`:option:. + This only works with `--mm:none`:option:, + `--mm:arc`:option: and `--mm:orc`:option:. `useRealtimeGC` Enables support of Nim's GC for *soft* realtime - systems. See the documentation of the `gc <gc.html>`_ + systems. See the documentation of the `mm <mm.html>`_ for further information. `logGC` Enable GC logging to stdout. `nodejs` The JS target is actually ``node.js``. @@ -614,9 +614,9 @@ A good start is to use the `any` operating target together with the .. code:: cmd - nim c --os:any --gc:arc -d:useMalloc [...] x.nim + nim c --os:any --mm:arc -d:useMalloc [...] x.nim -- `--gc:arc`:option: will enable the reference counting memory management instead +- `--mm:arc`:option: will enable the reference counting memory management instead of the default garbage collector. This enables Nim to use heap memory which is required for strings and seqs, for example. @@ -654,7 +654,7 @@ devices. This allocator gets blocks/pages of memory via a currently undocumented `osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap` is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc` define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently -only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6) +only supported with `--mm:arc` or `--mm:orc`. (Since version 1.6) nimPage256 / nimPage512 / nimPage1k =================================== @@ -681,19 +681,19 @@ nimMemAlignTiny Sets `MemAlign` to `4` bytes which reduces the memory alignment to better match some embedded devices. -Thread stack size +Thread stack size ================= Nim's thread API provides a simple wrapper around more advanced RTOS task features. Customizing the stack size and stack guard size can be done by setting `-d:nimThreadStackSize=16384` or `-d:nimThreadStackGuard=32`. -Currently only Zephyr and FreeRTOS support these configurations. +Currently only Zephyr and FreeRTOS support these configurations. Nim for realtime systems ======================== -See the documentation of Nim's soft realtime `GC <gc.html>`_ for further +See the `--mm:arc` or `--mm:orc` memory management settings in `MM <mm.html>`_ for further information. diff --git a/doc/gc.rst b/doc/refc.rst index 5de02f73d..766097f23 100644 --- a/doc/gc.rst +++ b/doc/refc.rst @@ -1,81 +1,3 @@ -======================= -Nim's Memory Management -======================= - -.. default-role:: code -.. include:: rstcommon.rst - -:Author: Andreas Rumpf -:Version: |nimversion| - -.. - - - "The road to hell is paved with good intentions." - - -Introduction -============ - -A memory-management algorithm optimal for every use-case cannot exist. -Nim provides multiple paradigms for needs ranging from large multi-threaded -applications, to games, hard-realtime systems and small microcontrollers. - -This document describes how the management strategies work; -How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:, -and how the memory management strategies other than garbage collectors work. - -.. note:: the default GC is incremental, thread-local and not "stop-the-world" - -Multi-paradigm Memory Management Strategies -=========================================== - -.. default-role:: option - -To choose the memory management strategy use the `--gc:` switch. - ---gc:refc This is the default GC. It's a - deferred reference counting based garbage collector - with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. ---gc:markAndSweep Simple Mark-And-Sweep based garbage collector. - Heaps are thread-local. ---gc:boehm Boehm based garbage collector, it offers a shared heap. ---gc:go Go's garbage collector, useful for interoperability with Go. - Offers a shared heap. ---gc:arc Plain reference counting with - `move semantic optimizations <destructors.html#move-semantics>`_, offers a shared heap. - It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles - cause memory leaks, beware. - ---gc:orc Same as `--gc:arc` but adds a cycle collector based on "trial deletion". - Unfortunately, that makes its performance profile hard to reason about so it is less - useful for hard real-time systems. - ---gc:none No memory management strategy nor a garbage collector. Allocated memory is - simply never freed. You should use `--gc:arc` instead. - - -================== ======== ================= ============== =================== -Memory Management Heap Reference Cycles Stop-The-World Command line switch -================== ======== ================= ============== =================== -RefC Local Cycle Collector No `--gc:refc` -Mark & Sweep Local Cycle Collector No `--gc:markAndSweep` -ARC Shared Leak No `--gc:arc` -ORC Shared Cycle Collector No `--gc:orc` -Boehm Shared Cycle Collector Yes `--gc:boehm` -Go Shared Cycle Collector Yes `--gc:go` -None Manual Manual Manual `--gc:none` -================== ======== ================= ============== =================== - -.. default-role:: code -.. include:: rstcommon.rst - -JavaScript's garbage collector is used for the `JavaScript and NodeJS -<backends.html#backends-the-javascript-target>`_ compilation targets. -The `NimScript <nims.html>`_ target uses the memory management strategy built into -the Nim compiler. - - Tweaking the refc GC ==================== @@ -164,6 +86,35 @@ that up to 100 objects are traversed and freed before it checks again. Thus highly specialized environments or for older hardware. +Thread coordination +------------------- + +When the `NimMain()` function is called Nim initializes the garbage +collector to the current thread, which is usually the main thread of your +application. If your C code later spawns a different thread and calls Nim +code, the garbage collector will fail to work properly and you will crash. + +As long as you don't use the threadvar emulation Nim uses native thread +variables, of which you get a fresh version whenever you create a thread. You +can then attach a GC to this thread via + +.. code-block:: nim + + system.setupForeignThreadGc() + +It is **not** safe to disable the garbage collector and enable it after the +call from your background thread even if the code you are calling is short +lived. + +Before the thread exits, you should tear down the thread's GC to prevent memory +leaks by calling + +.. code-block:: nim + + system.tearDownForeignThreadGc() + + + Keeping track of memory ======================= @@ -178,7 +129,7 @@ Other useful procs from `system <system.html>`_ you can use to keep track of mem * `GC_getStatistics()` Garbage collector statistics as a human-readable string. These numbers are usually only for the running thread, not for the whole heap, -with the exception of `--gc:boehm`:option: and `--gc:go`:option:. +with the exception of `--mm:boehm`:option: and `--mm:go`:option:. In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`. diff --git a/koch.nim b/koch.nim index f87828cdc..295b1584b 100644 --- a/koch.nim +++ b/koch.nim @@ -604,7 +604,7 @@ proc runCI(cmd: string) = when not defined(bsd): # the BSDs are overwhelmed already, so only run this test on the other machines: - kochExecFold("Boot Nim ORC", "boot -d:release --gc:orc --lib:lib") + kochExecFold("Boot Nim ORC", "boot -d:release --mm:orc --lib:lib") proc testUnixInstall(cmdLineRest: string) = csource("-d:danger" & cmdLineRest) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 70ee5ad07..4fbea8c77 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -129,7 +129,7 @@ tut2.rst tut3.rst nimc.rst niminst.rst -gc.rst +mm.rst """.splitWhitespace().mapIt("doc" / it) doc0 = """ |