Skip to content

Commit 8e2a707

Browse files
committed
1 parent c42eed3 commit 8e2a707

File tree

4 files changed

+126
-21
lines changed

4 files changed

+126
-21
lines changed

4.x/bindings/callbacks/index.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,17 @@
14851485
</ul>
14861486
</nav>
14871487

1488+
</li>
1489+
1490+
<li class="md-nav__item">
1491+
<a href="#memory-management" class="md-nav__link">
1492+
<span class="md-ellipsis">
1493+
1494+
Memory Management
1495+
1496+
</span>
1497+
</a>
1498+
14881499
</li>
14891500

14901501
</ul>
@@ -3640,6 +3651,14 @@ <h3 id="libffi-callback">LibFFI Callback<a class="headerlink" href="#libffi-call
36403651
<div class="highlight"><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="nb">abort</span><span class="w"> </span><span class="s2">&quot;libffi not found&quot;</span><span class="w"> </span><span class="k">unless</span><span class="w"> </span><span class="n">have_libffi</span>
36413652
</code></pre></div>
36423653
<p>If you are using CMake, you will need to add a C++ preprocessor define called <code>HAVE_LIBFFI</code> and link to libffi.</p>
3654+
<h2 id="memory-management">Memory Management<a class="headerlink" href="#memory-management" title="Permanent link">&para;</a></h2>
3655+
<p>Callback wrappers (NativeCallback instances) are intentionally never freed. This is because:</p>
3656+
<ol>
3657+
<li>C code may call the callback at any time, even after the Ruby code that registered it has finished executing</li>
3658+
<li>Ruby users commonly pass blocks to C callbacks, which Rice converts to Procs internally. Without special handling, these Procs would be garbage collected and the callback would crash when invoked</li>
3659+
</ol>
3660+
<p>Rice uses <code>Pin</code> internally to prevent the Ruby Proc from being garbage collected, ensuring the callback remains valid for the lifetime of the program.</p>
3661+
<p>In practice, this means each unique callback registration consumes a small amount of memory that is never reclaimed. For most applications this is not a concern, as callbacks are typically registered once during initialization.</p>
36433662

36443663

36453664

4.x/bindings/memory_management/index.html

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,6 +1756,45 @@
17561756
</span>
17571757
</a>
17581758

1759+
<nav class="md-nav" aria-label="Heap">
1760+
<ul class="md-nav__list">
1761+
1762+
<li class="md-nav__item">
1763+
<a href="#pin-api" class="md-nav__link">
1764+
<span class="md-ellipsis">
1765+
1766+
Pin API
1767+
1768+
</span>
1769+
</a>
1770+
1771+
</li>
1772+
1773+
<li class="md-nav__item">
1774+
<a href="#copy-semantics" class="md-nav__link">
1775+
<span class="md-ellipsis">
1776+
1777+
Copy Semantics
1778+
1779+
</span>
1780+
</a>
1781+
1782+
</li>
1783+
1784+
<li class="md-nav__item">
1785+
<a href="#when-to-use-pin-vs-ruby_mark" class="md-nav__link">
1786+
<span class="md-ellipsis">
1787+
1788+
When to Use Pin vs ruby_mark
1789+
1790+
</span>
1791+
</a>
1792+
1793+
</li>
1794+
1795+
</ul>
1796+
</nav>
1797+
17591798
</li>
17601799

17611800
<li class="md-nav__item">
@@ -3821,25 +3860,57 @@ <h2 id="c-referencing-ruby-objects">C++ Referencing Ruby Objects<a class="header
38213860
<h3 id="stack">Stack<a class="headerlink" href="#stack" title="Permanent link">&para;</a></h3>
38223861
<p>If you are working with VALUEs or Objects stored on the stack, the Ruby garbage collector will try to find them automatically. However, optimizing compilers may prevent them from doing so. Thus you may need to use Ruby's <a href="https://docs.ruby-lang.org/en/3.2/extension_rdoc.html#label-Appendix+E.+RB_GC_GUARD+to+protect+from+premature+GC">RB_GC_GUARD</a> macro</p>
38233862
<h3 id="heap">Heap<a class="headerlink" href="#heap" title="Permanent link">&para;</a></h3>
3824-
<p>If you allocate an Object on the heap or if it is a member of an object that might be allocated on the heap, use <code>Rice::Address_Registration_Guard</code> to register the object with the garbage collector.</p>
3863+
<p>If a C++ object holds a Ruby VALUE and that C++ object is <em>not</em> wrapped by Ruby (i.e., it's allocated on the heap or is a standalone object), use <code>Rice::Pin</code> to prevent the garbage collector from collecting the Ruby object.</p>
3864+
<div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="k">class</span><span class="w"> </span><span class="nc">Container</span>
3865+
<a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="p">{</span>
3866+
<a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="k">public</span><span class="o">:</span>
3867+
<a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="w"> </span><span class="n">Container</span><span class="p">(</span><span class="n">VALUE</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">pin_</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{}</span>
3868+
<a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="w"> </span><span class="n">VALUE</span><span class="w"> </span><span class="n">getValue</span><span class="p">()</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">pin_</span><span class="p">.</span><span class="n">get</span><span class="p">();</span><span class="w"> </span><span class="p">}</span>
3869+
<a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">setValue</span><span class="p">(</span><span class="n">VALUE</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">pin_</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">value</span><span class="p">);</span><span class="w"> </span><span class="p">}</span>
3870+
<a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a>
3871+
<a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="k">private</span><span class="o">:</span>
3872+
<a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="w"> </span><span class="n">Rice</span><span class="o">::</span><span class="n">Pin</span><span class="w"> </span><span class="n">pin_</span><span class="p">;</span>
3873+
<a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a><span class="p">};</span>
3874+
</code></pre></div>
3875+
<h4 id="pin-api">Pin API<a class="headerlink" href="#pin-api" title="Permanent link">&para;</a></h4>
3876+
<ul>
3877+
<li><code>Pin(VALUE value)</code> - Construct a Pin that protects the given VALUE from garbage collection</li>
3878+
<li><code>VALUE get() const</code> - Retrieve the pinned VALUE</li>
3879+
<li><code>void set(VALUE value)</code> - Replace the pinned VALUE</li>
3880+
</ul>
3881+
<h4 id="copy-semantics">Copy Semantics<a class="headerlink" href="#copy-semantics" title="Permanent link">&para;</a></h4>
3882+
<p><code>Pin</code> uses shared ownership internally. When you copy a <code>Pin</code>, both copies share the same underlying GC anchor:</p>
3883+
<div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="n">Pin</span><span class="w"> </span><span class="nf">pin1</span><span class="p">(</span><span class="n">some_value</span><span class="p">);</span>
3884+
<a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="n">Pin</span><span class="w"> </span><span class="n">pin2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pin1</span><span class="p">;</span><span class="w"> </span><span class="c1">// pin1 and pin2 share the same anchor</span>
3885+
<a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a>
3886+
<a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a><span class="n">pin1</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">other_value</span><span class="p">);</span><span class="w"> </span><span class="c1">// Both pin1.get() and pin2.get() now return other_value</span>
3887+
</code></pre></div>
3888+
<p>This is useful when multiple C++ objects need to reference the same Ruby object - only one GC registration is needed.</p>
3889+
<h4 id="when-to-use-pin-vs-ruby_mark">When to Use Pin vs ruby_mark<a class="headerlink" href="#when-to-use-pin-vs-ruby_mark" title="Permanent link">&para;</a></h4>
3890+
<p>Use <code>Pin</code> when:
3891+
* The C++ object is <strong>not</strong> wrapped by Ruby (e.g., created with <code>new</code> in C++, stored in a global, or part of a C++ library's internal data structures)
3892+
* You want self-contained protection without manual GC registration</p>
3893+
<p>Use <code>ruby_mark</code> (see below) when:
3894+
* The C++ object <strong>is</strong> wrapped by Ruby via <code>Data_Type</code>
3895+
* Ruby owns the C++ object and will call the mark function during garbage collection</p>
38253896
<h3 id="member-variables">Member Variables<a class="headerlink" href="#member-variables" title="Permanent link">&para;</a></h3>
38263897
<p>If you create classes or structures that reference Ruby objects, you need to implement a custom <code>ruby_mark</code> function:</p>
3827-
<div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="k">class</span><span class="w"> </span><span class="nc">MyClass</span>
3828-
<a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="p">{</span>
3829-
<a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span><span class="n">VALUE</span><span class="w"> </span><span class="n">value_</span><span class="p">;</span>
3830-
<a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="p">}</span>
3831-
<a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a>
3832-
<a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="k">namespace</span><span class="w"> </span><span class="nn">Rice</span>
3833-
<a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="p">{</span>
3834-
<a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="w"> </span><span class="k">template</span><span class="o">&lt;&gt;</span>
3835-
<a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="w"> </span><span class="n">ruby_mark</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">MyClass</span><span class="o">*</span><span class="w"> </span><span class="n">myClass</span><span class="p">)</span>
3836-
<a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a><span class="w"> </span><span class="p">{</span>
3837-
<a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a><span class="w"> </span><span class="n">rb_gc_mark</span><span class="p">(</span><span class="n">myClass</span><span class="o">-&gt;</span><span class="n">value_</span><span class="p">);</span>
3838-
<a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a><span class="w"> </span><span class="p">}</span>
3839-
<a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a><span class="p">}</span>
3840-
<a id="__codelineno-10-14" name="__codelineno-10-14" href="#__codelineno-10-14"></a>
3841-
<a id="__codelineno-10-15" name="__codelineno-10-15" href="#__codelineno-10-15"></a><span class="n">Data_Type</span><span class="o">&lt;</span><span class="n">MyClass</span><span class="o">&gt;</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">define_class</span><span class="o">&lt;</span><span class="n">MyClass</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&quot;MyClass&quot;</span><span class="p">)</span>
3842-
<a id="__codelineno-10-16" name="__codelineno-10-16" href="#__codelineno-10-16"></a><span class="w"> </span><span class="p">.</span><span class="n">define_constructor</span><span class="p">(</span><span class="n">Constructor</span><span class="o">&lt;</span><span class="n">MyClass</span><span class="o">&gt;</span><span class="p">());</span>
3898+
<div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="k">class</span><span class="w"> </span><span class="nc">MyClass</span>
3899+
<a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="p">{</span>
3900+
<a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a><span class="w"> </span><span class="n">VALUE</span><span class="w"> </span><span class="n">value_</span><span class="p">;</span>
3901+
<a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a><span class="p">}</span>
3902+
<a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a>
3903+
<a id="__codelineno-12-6" name="__codelineno-12-6" href="#__codelineno-12-6"></a><span class="k">namespace</span><span class="w"> </span><span class="nn">Rice</span>
3904+
<a id="__codelineno-12-7" name="__codelineno-12-7" href="#__codelineno-12-7"></a><span class="p">{</span>
3905+
<a id="__codelineno-12-8" name="__codelineno-12-8" href="#__codelineno-12-8"></a><span class="w"> </span><span class="k">template</span><span class="o">&lt;&gt;</span>
3906+
<a id="__codelineno-12-9" name="__codelineno-12-9" href="#__codelineno-12-9"></a><span class="w"> </span><span class="n">ruby_mark</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">MyClass</span><span class="o">*</span><span class="w"> </span><span class="n">myClass</span><span class="p">)</span>
3907+
<a id="__codelineno-12-10" name="__codelineno-12-10" href="#__codelineno-12-10"></a><span class="w"> </span><span class="p">{</span>
3908+
<a id="__codelineno-12-11" name="__codelineno-12-11" href="#__codelineno-12-11"></a><span class="w"> </span><span class="n">rb_gc_mark</span><span class="p">(</span><span class="n">myClass</span><span class="o">-&gt;</span><span class="n">value_</span><span class="p">);</span>
3909+
<a id="__codelineno-12-12" name="__codelineno-12-12" href="#__codelineno-12-12"></a><span class="w"> </span><span class="p">}</span>
3910+
<a id="__codelineno-12-13" name="__codelineno-12-13" href="#__codelineno-12-13"></a><span class="p">}</span>
3911+
<a id="__codelineno-12-14" name="__codelineno-12-14" href="#__codelineno-12-14"></a>
3912+
<a id="__codelineno-12-15" name="__codelineno-12-15" href="#__codelineno-12-15"></a><span class="n">Data_Type</span><span class="o">&lt;</span><span class="n">MyClass</span><span class="o">&gt;</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">define_class</span><span class="o">&lt;</span><span class="n">MyClass</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&quot;MyClass&quot;</span><span class="p">)</span>
3913+
<a id="__codelineno-12-16" name="__codelineno-12-16" href="#__codelineno-12-16"></a><span class="w"> </span><span class="p">.</span><span class="n">define_constructor</span><span class="p">(</span><span class="n">Constructor</span><span class="o">&lt;</span><span class="n">MyClass</span><span class="o">&gt;</span><span class="p">());</span>
38433914
</code></pre></div>
38443915

38453916

4.x/changelog/index.html

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3919,9 +3919,24 @@ <h2 id="492-unreleased">4.9.2 (unreleased)<a class="headerlink" href="#492-unrel
39193919
* Add support for <code>std::ostream</code>, <code>std::ostringstream</code>, and <code>std::ofstream</code>. Ruby can write to C++ streams and pass them to C++ functions. Standard streams are exposed as <code>Std::COUT</code> and <code>Std::CERR</code>.</p>
39203920
<p>Internal:
39213921
* Refactor type handling by merging <code>TypeMapper</code> into <code>TypeDetail</code> and simplifying class hierarchy</p>
3922-
<p>Incomptatible Changes:
3923-
* Rice converts Ruby blocks to procs. Thus if you have a method that expects a block, you must add
3924-
a VALUE parameter and tell Rice it is a value. For example:</p>
3922+
<p>Incompatible Changes:
3923+
* <code>Address_Registration_Guard</code> has been replaced by <code>Pin</code>. If you are using <code>Address_Registration_Guard</code>
3924+
to protect Ruby VALUEs from garbage collection, update your code to use <code>Pin</code> instead:</p>
3925+
<p>Before:
3926+
<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="n">VALUE</span><span class="w"> </span><span class="n">value_</span><span class="p">;</span>
3927+
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="n">Address_Registration_Guard</span><span class="w"> </span><span class="n">guard_</span><span class="p">;</span>
3928+
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="n">MyClass</span><span class="p">()</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">value_</span><span class="p">(</span><span class="n">rb_str_new2</span><span class="p">(</span><span class="s">&quot;test&quot;</span><span class="p">)),</span><span class="w"> </span><span class="n">guard_</span><span class="p">(</span><span class="o">&amp;</span><span class="n">value_</span><span class="p">)</span><span class="w"> </span><span class="p">{}</span>
3929+
</code></pre></div></p>
3930+
<p>After:
3931+
<div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="n">Pin</span><span class="w"> </span><span class="n">pin_</span><span class="p">;</span>
3932+
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="n">MyClass</span><span class="p">()</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">pin_</span><span class="p">(</span><span class="n">rb_str_new2</span><span class="p">(</span><span class="s">&quot;test&quot;</span><span class="p">))</span><span class="w"> </span><span class="p">{}</span>
3933+
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="n">VALUE</span><span class="w"> </span><span class="n">getValue</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">pin_</span><span class="p">.</span><span class="n">get</span><span class="p">();</span><span class="w"> </span><span class="p">}</span>
3934+
</code></pre></div></p>
3935+
<p><code>Pin</code> is self-contained and provides <code>get()</code> and <code>set()</code> methods to access the pinned VALUE.</p>
3936+
<ul>
3937+
<li>Rice converts Ruby blocks to procs. Thus if you have a method that expects a block, you must add
3938+
a VALUE parameter and tell Rice it is a value. For example:</li>
3939+
</ul>
39253940
<p>define_method("my_method", <a href="VALUE self, VALUE proc"></a>
39263941
{
39273942
}, Arg("proc").setValue())</p>

4.x/search/search_index.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)