diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /devtools/docs/user/memory/dominators | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/docs/user/memory/dominators')
6 files changed, 105 insertions, 0 deletions
diff --git a/devtools/docs/user/memory/dominators/index.rst b/devtools/docs/user/memory/dominators/index.rst new file mode 100644 index 0000000000..443b4c6e7b --- /dev/null +++ b/devtools/docs/user/memory/dominators/index.rst @@ -0,0 +1,85 @@ +========== +Dominators +========== + +This article provides an introduction to the concepts of *Reachability*, *Shallow* versus *Retained* size, and *Dominators*, as they apply in garbage-collected languages like JavaScript. + +These concepts matter in memory analysis, because often an object may itself be small, but may hold references to other much larger objects, and by doing this will prevent the garbage collector from freeing that extra memory. + +You can see the dominators in a page using the :doc:`Dominators view <../dominators_view/index>` in the Memory tool. + + +With a garbage-collected language, like JavaScript, the programmer doesn't generally have to worry about deallocating memory. They can just create and use objects, and when the objects are no longer needed, the runtime takes care of cleaning up, and frees the memory the objects occupied. + + +.. _memory-dominators-reachability: + +Reachability +************ + +In modern JavaScript implementations, the runtime decides whether an object is no longer needed based on *reachability*. In this system the heap is represented as one or more graphs. Each node in the graph represents an object, and each connection between nodes (edge) represents a reference from one object to another. The graph starts at a root node, indicated in these diagrams with "R". + +.. image:: memory-graph.svg + :class: center + + +During garbage collection, the runtime traverses the graph, starting at the root, and marks every object it finds. Any objects it doesn't find are unreachable, and can be deallocated. + +So when an object becomes unreachable (for example, because it is only referenced by a single local variable which goes out of scope) then any objects it references also become unreachable, as long as no other objects reference them: + +.. image:: memory-graph-unreachable.svg + :class: center + + +Conversely, this means that objects are kept alive as long as some other reachable object is holding a reference to them. + + +.. _shallow-and-retained-size: + +Shallow and retained size +************************* + +This gives rise to a distinction between two ways to look at the size of an object: + + +- *shallow size*: the size of the object itself +- *retained size*: the size of the object itself, plus the size of other objects that are kept alive by this object + + +Often, objects will have a small shallow size but a much larger retained size, through the references they contain to other objects. Retained size is an important concept in analyzing memory usage, because it answers the question "if this object ceases to exist, what's the total amount of memory freed?". + + +Dominators +********** + +A related concept is that of the *dominator*. Node B is said to dominate node A if every path from the root to A passes through B: + +.. image:: memory-graph-dominators.svg + :class: center + + +If any of node A's dominators are freed, then node A itself becomes eligible for garbage collection. + + +.. _memory-dominators-immediate-dominator: + +If node B dominates node A, but does not dominate any of A's other dominators, then B is the *immediate dominator* of A: + +.. image:: memory-graph-immediate-dominator.svg + :class: center + + +.. _memory-dominators-multiple-paths: + +One slight subtlety here is that if an object A is referenced by two other unrelated objects B and C, then neither object is its dominator, because you could remove either B or C from the graph, and A would still be retained by its other referrer. Instead, the immediate dominator of A would be its first common ancestor: + +.. image:: memory-graph-dominator-multiple-references.svg + :class: center + + +See also +******** + + +- `Dominators in graph theory <https://en.wikipedia.org/wiki/Dominator_%28graph_theory%29>`_. +- `Tracing garbage collection <https://en.wikipedia.org/wiki/Tracing_garbage_collection>`_. diff --git a/devtools/docs/user/memory/dominators/memory-graph-dominator-multiple-references.svg b/devtools/docs/user/memory/dominators/memory-graph-dominator-multiple-references.svg new file mode 100644 index 0000000000..4ac6b45812 --- /dev/null +++ b/devtools/docs/user/memory/dominators/memory-graph-dominator-multiple-references.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" viewBox="114 20 158 212" width="158pt" height="212pt"><defs><linearGradient x1="0" x2="1" id="a" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e5f2f2"/><stop offset="1" stop-color="#cff2f2"/></linearGradient><linearGradient id="b" xl:href="#a" gradientTransform="matrix(0 38 -38 0 183 90.5)"/><linearGradient id="c" xl:href="#a" gradientTransform="matrix(0 38 -38 0 135 141.5)"/><linearGradient id="d" xl:href="#a" gradientTransform="rotate(90 44.5 186) scale(38)"/><linearGradient id="f" xl:href="#a" gradientTransform="matrix(0 38 -38 0 183 191.5)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="e" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0L0-3v6z" fill="currentColor" stroke="currentColor"/></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="g" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0H0m0-3l8 3-8 3" fill="none" stroke="currentColor"/></marker></defs><g fill="none"><circle cx="183" cy="109.5" r="19" fill="url(#b)"/><circle cx="183" cy="109.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="135" cy="160.5" r="19" fill="url(#c)"/><circle cx="135" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="230.5" cy="160.5" r="19" fill="url(#d)"/><circle cx="230.5" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M169.978 123.336l-15.171 16.119m41.143-16.051l14.853 15.948"/><circle cx="183" cy="210.5" r="19" fill="url(#f)"/><circle cx="183" cy="210.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><text transform="translate(172.8 201.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="5.016" y="15" textLength="10.368">A</tspan></text><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M148.158 174.206l14.828 15.446"/><text transform="translate(169 26.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x=".096" y="15" textLength="10.368">A</tspan><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="9.28" y="15" textLength="4.448">’</tspan><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="12.544" y="15" textLength="85.36">s dominator</tspan></text><path marker-end="url(#g)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4,4" d="M210.905 50.5l-15.546 32.87"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M217.414 174.275l-14.509 15.272"/></g></svg>
\ No newline at end of file diff --git a/devtools/docs/user/memory/dominators/memory-graph-dominators.svg b/devtools/docs/user/memory/dominators/memory-graph-dominators.svg new file mode 100644 index 0000000000..e3a63c96df --- /dev/null +++ b/devtools/docs/user/memory/dominators/memory-graph-dominators.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" viewBox="60 57 353 232" width="353pt" height="232pt"><defs><linearGradient x1="0" x2="1" id="a" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e5f2f2"/><stop offset="1" stop-color="#cff2f2"/></linearGradient><linearGradient id="b" xl:href="#a" gradientTransform="matrix(0 38 -38 0 183 90.5)"/><linearGradient id="c" xl:href="#a" gradientTransform="matrix(0 38 -38 0 135 141.5)"/><linearGradient id="d" xl:href="#a" gradientTransform="rotate(90 44.5 186) scale(38)"/><linearGradient id="f" xl:href="#a" gradientTransform="matrix(0 38 -38 0 81.5 196.5)"/><linearGradient id="g" xl:href="#a" gradientTransform="rotate(90 41 238.5) scale(38)"/><linearGradient id="h" xl:href="#a" gradientTransform="rotate(90 -8.5 240) scale(38)"/><linearGradient id="i" xl:href="#a" gradientTransform="matrix(0 38 -38 0 327 248.5)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="e" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0L0-3v6z" fill="currentColor" stroke="currentColor"/></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="j" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0H0m0-3l8 3-8 3" fill="none" stroke="currentColor"/></marker></defs><g fill="none"><circle cx="183" cy="109.5" r="19" fill="url(#b)"/><circle cx="183" cy="109.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><text transform="translate(172.8 100.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="4.72" y="15" textLength="10.96">R</tspan></text><circle cx="135" cy="160.5" r="19" fill="url(#c)"/><circle cx="135" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="230.5" cy="160.5" r="19" fill="url(#d)"/><circle cx="230.5" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M169.978 123.336l-15.171 16.119m41.143-16.051l14.853 15.948"/><circle cx="81.5" cy="215.5" r="19" fill="url(#f)"/><circle cx="81.5" cy="215.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M121.752 174.119l-20.101 20.665"/><circle cx="279.5" cy="216.5" r="19" fill="url(#g)"/><circle cx="279.5" cy="216.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="231.5" cy="267.5" r="19" fill="url(#h)"/><circle cx="231.5" cy="267.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="327" cy="267.5" r="19" fill="url(#i)"/><circle cx="327" cy="267.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><text transform="translate(316.8 258.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="5.016" y="15" textLength="10.368">A</tspan></text><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M243.012 174.799l17.457 19.951m31.981 35.654l14.853 15.948m-40.825-16.016l-15.171 16.119"/><text transform="translate(301.5 63)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x=".096" y="15" textLength="10.368">A</tspan><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="9.28" y="15" textLength="4.448">’</tspan><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="12.544" y="15" textLength="93.36">s dominators</tspan></text><path marker-end="url(#j)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4,4" d="M296.5 84.682l-85.265 18.644M333.483 87l-79.457 56.709M346.715 87l-53.899 103.845"/></g></svg>
\ No newline at end of file diff --git a/devtools/docs/user/memory/dominators/memory-graph-immediate-dominator.svg b/devtools/docs/user/memory/dominators/memory-graph-immediate-dominator.svg new file mode 100644 index 0000000000..8288524884 --- /dev/null +++ b/devtools/docs/user/memory/dominators/memory-graph-immediate-dominator.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" viewBox="60 57 350 232" width="350pt" height="232pt"><defs><linearGradient x1="0" x2="1" id="a" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e5f2f2"/><stop offset="1" stop-color="#cff2f2"/></linearGradient><linearGradient id="b" xl:href="#a" gradientTransform="matrix(0 38 -38 0 183 90.5)"/><linearGradient id="c" xl:href="#a" gradientTransform="matrix(0 38 -38 0 135 141.5)"/><linearGradient id="d" xl:href="#a" gradientTransform="rotate(90 44.5 186) scale(38)"/><linearGradient id="f" xl:href="#a" gradientTransform="matrix(0 38 -38 0 81.5 196.5)"/><linearGradient id="g" xl:href="#a" gradientTransform="rotate(90 41 238.5) scale(38)"/><linearGradient id="h" xl:href="#a" gradientTransform="rotate(90 -8.5 240) scale(38)"/><linearGradient id="i" xl:href="#a" gradientTransform="matrix(0 38 -38 0 327 248.5)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="e" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0L0-3v6z" fill="currentColor" stroke="currentColor"/></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="j" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0H0m0-3l8 3-8 3" fill="none" stroke="currentColor"/></marker></defs><g fill="none"><circle cx="183" cy="109.5" r="19" fill="url(#b)"/><circle cx="183" cy="109.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><text transform="translate(172.8 100.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="4.72" y="15" textLength="10.96">R</tspan></text><circle cx="135" cy="160.5" r="19" fill="url(#c)"/><circle cx="135" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="230.5" cy="160.5" r="19" fill="url(#d)"/><circle cx="230.5" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M169.978 123.336l-15.171 16.119m41.143-16.051l14.853 15.948"/><circle cx="81.5" cy="215.5" r="19" fill="url(#f)"/><circle cx="81.5" cy="215.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M121.752 174.119l-20.101 20.665"/><circle cx="279.5" cy="216.5" r="19" fill="url(#g)"/><circle cx="279.5" cy="216.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="231.5" cy="267.5" r="19" fill="url(#h)"/><circle cx="231.5" cy="267.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="327" cy="267.5" r="19" fill="url(#i)"/><circle cx="327" cy="267.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><text transform="translate(316.8 258.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="5.016" y="15" textLength="10.368">A</tspan></text><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M243.012 174.799l17.457 19.951m31.981 35.654l14.853 15.948m-40.825-16.016l-15.171 16.119"/><text transform="translate(304.5 62)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x=".2" y="15" textLength="10.368">A</tspan><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="9.384" y="15" textLength="4.448">’</tspan><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="12.648" y="15" textLength="87.152">s immediate</tspan><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="13.544" y="33" textLength="72.912">dominator</tspan></text><path marker-end="url(#j)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4,4" d="M341.863 103l-48.444 88.167"/></g></svg>
\ No newline at end of file diff --git a/devtools/docs/user/memory/dominators/memory-graph-unreachable.svg b/devtools/docs/user/memory/dominators/memory-graph-unreachable.svg new file mode 100644 index 0000000000..62abb0e016 --- /dev/null +++ b/devtools/docs/user/memory/dominators/memory-graph-unreachable.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" viewBox="60 88 287 200" width="287pt" height="200pt"><defs><linearGradient x1="0" x2="1" id="a" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e5f2f2"/><stop offset="1" stop-color="#cff2f2"/></linearGradient><linearGradient id="c" xl:href="#a" gradientTransform="matrix(0 38 -38 0 183 90.5)"/><linearGradient id="d" xl:href="#a" gradientTransform="matrix(0 38 -38 0 135 141.5)"/><linearGradient id="e" xl:href="#a" gradientTransform="rotate(90 44.5 186) scale(38)"/><linearGradient x1="0" x2="1" id="b" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f29a8b"/><stop offset="1" stop-color="#f23d1c"/></linearGradient><linearGradient id="f" xl:href="#b" gradientTransform="rotate(90 41 237.5) scale(38)"/><linearGradient id="g" xl:href="#b" gradientTransform="rotate(90 -8.5 239) scale(38)"/><linearGradient id="h" xl:href="#b" gradientTransform="matrix(0 38 -38 0 326 247.5)"/><linearGradient id="j" xl:href="#a" gradientTransform="matrix(0 38 -38 0 81.5 196.5)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="i" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0L0-3v6z" fill="currentColor" stroke="currentColor"/></marker></defs><g fill="none"><circle cx="183" cy="109.5" r="19" fill="url(#c)"/><circle cx="183" cy="109.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><text transform="translate(172.8 100.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="4.72" y="15" textLength="10.96">R</tspan></text><circle cx="135" cy="160.5" r="19" fill="url(#d)"/><circle cx="135" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="230.5" cy="160.5" r="19" fill="url(#e)"/><circle cx="230.5" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="278.5" cy="215.5" r="19" fill="url(#f)"/><circle cx="278.5" cy="215.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="230.5" cy="266.5" r="19" fill="url(#g)"/><circle cx="230.5" cy="266.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="326" cy="266.5" r="19" fill="url(#h)"/><circle cx="326" cy="266.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#i)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M169.978 123.336l-15.171 16.119m41.143-16.051l14.853 15.948m54.675 89.984l-15.171 16.119m41.143-16.051l14.853 15.948"/><circle cx="81.5" cy="215.5" r="19" fill="url(#j)"/><circle cx="81.5" cy="215.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#i)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M121.752 174.119l-20.101 20.665"/></g></svg>
\ No newline at end of file diff --git a/devtools/docs/user/memory/dominators/memory-graph.svg b/devtools/docs/user/memory/dominators/memory-graph.svg new file mode 100644 index 0000000000..0b4ee2d64c --- /dev/null +++ b/devtools/docs/user/memory/dominators/memory-graph.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" viewBox="60 88 288 201" width="384" height="268"><defs><linearGradient x1="0" x2="1" id="a" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e5f2f2"/><stop offset="1" stop-color="#cff2f2"/></linearGradient><linearGradient id="b" xl:href="#a" gradientTransform="matrix(0 38 -38 0 183 90.5)"/><linearGradient id="c" xl:href="#a" gradientTransform="matrix(0 38 -38 0 135 141.5)"/><linearGradient id="d" xl:href="#a" gradientTransform="rotate(90 44.5 186) scale(38)"/><linearGradient id="f" xl:href="#a" gradientTransform="matrix(0 38 -38 0 81.5 196.5)"/><linearGradient id="g" xl:href="#a" gradientTransform="rotate(90 41 238.5) scale(38)"/><linearGradient id="h" xl:href="#a" gradientTransform="rotate(90 -8.5 240) scale(38)"/><linearGradient id="i" xl:href="#a" gradientTransform="matrix(0 38 -38 0 327 248.5)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="e" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="#000"><path d="M8 0L0-3v6z" fill="currentColor" stroke="currentColor"/></marker></defs><g fill="none"><circle cx="183" cy="109.5" r="19" fill="url(#b)"/><circle cx="183" cy="109.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><text transform="translate(172.8 100.5)" fill="#000"><tspan font-family="Helvetica Neue" font-size="16" font-weight="500" x="4.72" y="15" textLength="10.96">R</tspan></text><circle cx="135" cy="160.5" r="19" fill="url(#c)"/><circle cx="135" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="230.5" cy="160.5" r="19" fill="url(#d)"/><circle cx="230.5" cy="160.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M169.978 123.336l-15.171 16.119m41.143-16.051l14.853 15.948"/><circle cx="81.5" cy="215.5" r="19" fill="url(#f)"/><circle cx="81.5" cy="215.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M121.752 174.119l-20.101 20.665"/><circle cx="279.5" cy="216.5" r="19" fill="url(#g)"/><circle cx="279.5" cy="216.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="231.5" cy="267.5" r="19" fill="url(#h)"/><circle cx="231.5" cy="267.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><circle cx="327" cy="267.5" r="19" fill="url(#i)"/><circle cx="327" cy="267.5" r="19" stroke="#000" stroke-linecap="round" stroke-linejoin="round"/><path marker-end="url(#e)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M243.012 174.799l17.457 19.951m31.981 35.654l14.853 15.948m-40.825-16.016l-15.171 16.119"/></g></svg>
\ No newline at end of file |