Boost C++ Libraries: Ticket #12220: Memory leak in future::then() https://svn.boost.org/trac10/ticket/12220 <p> Since Boost 1.60, the continuation destructor is never called. </p> <p> I've reproduced the leak using Boost 1.61 with the attached program in following configurations: </p> <ul><li>GCC 5.3.0 with BOOST_THREAD_VERSION=2, BOOST_THREAD_PROVIDES_FUTURE, BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION </li><li>MSVC 14.0 with BOOST_THREAD_VERSION=2, BOOST_THREAD_PROVIDES_FUTURE, BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION </li><li>MSVC 14.0 with BOOST_THREAD_VERSION=4 </li></ul><p> Interestingly, the leak disappears with GCC 5.3.0 when BOOST_THREAD_VERSION=4. </p> <p> Also, there is no leak in any configuration for deferred launch policy. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12220 Trac 1.4.3 valentin.milea@… Sun, 22 May 2016 08:42:27 GMT attachment set https://svn.boost.org/trac10/ticket/12220 https://svn.boost.org/trac10/ticket/12220 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">future_then_leak.cpp</span> </li> </ul> Ticket Bloody Rookie Wed, 13 Jul 2016 10:45:47 GMT <link>https://svn.boost.org/trac10/ticket/12220#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:1</guid> <description> <p> I can confirm that for the mentioned Boost versions there is a problem with the lifetime of a future continuation. In Boost 1.60 the flag BOOST_THREAD_FUTURE_BLOCKING was introduced. For future continuations with async launch policy the flag is used in the future.hpp code in the following way: </p> <pre class="wiki">#ifdef BOOST_THREAD_FUTURE_BLOCKING this-&gt;thr_ = thread(&amp;future_async_shared_state::run, static_shared_from_this(this), boost::forward&lt;Fp&gt;(f)); #else thread(&amp;future_async_shared_state::run, static_shared_from_this(this), boost::forward&lt;Fp&gt;(f)).detach(); #endif </pre><p> If the flag is defined the thread is attached to the future_async_shared_state via the thr_ member variable. The thread holds a reference to the shared state in its thread_info member (note the static_shared_from_this(this) parameter). This leads to the situation that even after the thread finished its work making the future ready, the shared state still holds on to the thread and the thread structure still holds a reference to the shared state. This makes the future immortal and thus the resources are never released. </p> <p> A workaround is to undefine the flag. This has the side effect that the destructor of the future won't block which sometimes is undesirable (and which was the reason the flag was introduced). Using deferred launch policy doesn't lead to the memory leak since no new thread is launched for the execution of the continuation. </p> <p> Please respond to this ticket, a memory leak makes the continuations unusable. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 08 Aug 2016 23:07:16 GMT</pubDate> <title>owner, status changed https://svn.boost.org/trac10/ticket/12220#comment:2 https://svn.boost.org/trac10/ticket/12220#comment:2 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Anthony Williams</span> to <span class="trac-author">viboes</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket viboes Mon, 08 Aug 2016 23:07:49 GMT <link>https://svn.boost.org/trac10/ticket/12220#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:3</guid> <description> <p> Sorry for been late. I will take a look at asap. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Tue, 09 Aug 2016 00:16:45 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:4</guid> <description> <p> Why do you say that" The thread holds a reference to the shared state in its thread_info member (note the static_shared_from_this(this) parameter)."? static_shared_from_this(this) is used as parameter of the run function and the parameter is released when the function ends, isn't it? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 15 Aug 2016 18:22:51 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:5</guid> <description> <p> See also <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/11951" title="#11951: Bugs: Memory leak in boost::when_all (closed: fixed)">#11951</a> </p> </description> <category>Ticket</category> </item> <item> <dc:creator>BloodyRookie</dc:creator> <pubDate>Thu, 18 Aug 2016 19:23:37 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:6</guid> <description> <p> "static_shared_from_this(this) is used as parameter of the run function and the parameter is released when the function ends, isn't it?" </p> <p> Where is the parameter released? </p> <p> Suppose I have code like this </p> <pre class="wiki">{ auto f = boost::make_ready_future&lt;int&gt;(41).then([](boost::future&lt;int&gt;) { return 42; }); f.get(); // wait for the future to complete } </pre><p> Then at some point </p> <pre class="wiki">this-&gt;thr_ = thread(&amp;future_async_shared_state::run, static_shared_from_this(this), boost::forward&lt;Fp&gt;(f)); </pre><p> Is called. The thread ctor calls </p> <pre class="wiki">thread_info(make_thread_info(boost::bind(boost::type&lt;void&gt;(),f,a1))) </pre><p> a1 is </p> <p> boost::shared_ptr&lt;boost::detail::future_async_continuation_shared_state&lt;boost::future&lt;int&gt;,int,int &lt;lambda&gt;(boost::future&lt;int&gt;)&gt;&gt; </p> <p> The result of boost::bind is stored in the thread_data member (actually the pointer thread_data_ptr keeps it alive) </p> <p> After the future completes the situation has not changed, nothing is released imo. In the debugger I can see the following: </p> <p> <a class="ext-link" href="http://imgur.com/a/7u5ii"><span class="icon">​</span>http://imgur.com/a/7u5ii</a> </p> <p> There are 2 strong references on the shared state, one is from the variable f but the other one is from the creation of the thread which is attached to the future. The dtor of the future is never called. </p> <p> If I comment out the BOOST_THREAD_FUTURE_BLOCKING flag definition then at the same break point there is only 1 strong reference and the dtor of the future is called. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Fri, 19 Aug 2016 22:02:06 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:7</guid> <description> <p> I should use a weak_ptr instead but for the time been I don't reach to make it working. Any help much appreciated. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Fri, 19 Aug 2016 22:02:49 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:8</guid> <description> <p> See also <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/11951" title="#11951: Bugs: Memory leak in boost::when_all (closed: fixed)">#11951</a> </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 03 Sep 2016 12:07:01 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:9</guid> <description> <p> I have been trying to see how to fix these issues (See also <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/11951" title="#11951: Bugs: Memory leak in boost::when_all (closed: fixed)">#11951</a>) and I don't know how to fix them if the future must be blocking. </p> <p> As the Concurrent TS doesn't blocks in this cases, I believe that even if it is a breaking change I will create a new Boost.Thread version 5 that doesn't defines BOOST_THREAD_FUTURE_BLOCKING it by default. </p> <p> What others think? </p> <p> P.S. This couldn't be provided before Boost 1.63. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 03 Sep 2016 12:56:42 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:10</guid> <description> <p> I was thinking about this and instead of joining the thread I can just wait. IN this way I don't need to store the thread and the cycle will be broken. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 03 Sep 2016 15:20:17 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:11</guid> <description> <p> I have committed </p> <p> <a class="ext-link" href="https://github.com/boostorg/thread/commit/5450e98c6bd2515388de1d3d97431cf5374319e7"><span class="icon">​</span>https://github.com/boostorg/thread/commit/5450e98c6bd2515388de1d3d97431cf5374319e7</a> </p> <p> Please, could you tell me if this fixes the issue? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 03 Sep 2016 19:25:25 GMT</pubDate> <title>milestone changed https://svn.boost.org/trac10/ticket/12220#comment:12 https://svn.boost.org/trac10/ticket/12220#comment:12 <ul> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.62.0</span> </li> </ul> Ticket BloodyRookie Sun, 04 Sep 2016 14:55:15 GMT <link>https://svn.boost.org/trac10/ticket/12220#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:13</guid> <description> <p> I applied the patch and now the dtor is getting called indeed. Are there any disadvantages to the BOOST_THREAD_FUTURE_BLOCKING approach? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Tue, 06 Sep 2016 16:49:13 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12220#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12220#comment:14</guid> <description> <p> Thanks for testing. </p> <p> BOOST_THREAD_FUTURE_BLOCKING used the thread to join it. BOOST_THREAD_ASYNC_FUTURE_WAITS uses the future itself to wait. This avoid the shared_ptr cycle. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Tue, 06 Sep 2016 16:51:08 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/12220#comment:15 https://svn.boost.org/trac10/ticket/12220#comment:15 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> Ticket