-
Notifications
You must be signed in to change notification settings - Fork 397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Take causes memory leak #452
Comments
Yes, there are many circular references in rxcpp. These are broken by the unsubscribe signal. Is there an expression that actually demonstrates a leak? |
After producing a MCVE I'm not sure it is #include <rxcpp/rx.hpp>
#include <iostream>
struct foo : public rxcpp::sources::source_base<int> {
static int refcount;
explicit foo() { std::cout << "++refcount = " << ++refcount << '\n'; }
~foo() { std::cout << "--refcount = " << --refcount << '\n'; }
foo(const foo &other) { std::cout << "++refcount = " << ++refcount << '\n'; }
foo(foo &&) { std::cout << "++refcount = " << ++refcount << '\n'; }
foo &operator=(foo &&) = default;
foo &operator=(const foo &) = default;
template <typename Subscriber>
void on_subscribe(Subscriber subscriber) const {
for (auto i = 0; i < 100; ++i) {
subscriber.on_next(i);
}
subscriber.on_completed();
}
};
auto create_foo_observable() {
return rxcpp::observable<int, foo>{foo{}}
.lift<int>([](rxcpp::subscriber<int> subscriber) {
subscriber.get_subscription().add([] {
std::cout << "Unsubscribed (refcount = " << foo::refcount << ")\n";
});
return subscriber;
})
.as_dynamic();
}
int foo::refcount = 0;
int main() {
{
create_foo_observable()
.observe_on(rxcpp::observe_on_new_thread())
.take(10)
.as_blocking()
.subscribe([](auto) {});
}
std::cout << "Final refcount is " << foo::refcount << '\n';
}
If I remove |
If I use #include <rxcpp/rx.hpp>
struct bar {
static int refcount;
explicit bar() { std::cout << "++refcount = " << ++refcount << '\n'; }
~bar() { std::cout << "--refcount = " << --refcount << '\n'; }
bar(const bar &other) { std::cout << "++refcount = " << ++refcount << '\n'; }
bar(bar &&) { std::cout << "++refcount = " << ++refcount << '\n'; }
bar &operator=(bar &&) = default;
bar &operator=(const bar &) = default;
};
int bar::refcount = 0;
int main() {
{
rxcpp::observable<>::create<int>([state = bar{}](auto subscriber) {
for (auto i = 0; i < 100; ++i) {
subscriber.on_next(i);
}
subscriber.on_completed();
})
.observe_on(rxcpp::observe_on_new_thread())
.take(10)
.as_blocking()
.subscribe([](auto) {});
}
// <- Need to wait for cleanup or `bar::refcount == 1`
using namespace std::chrono_literals;
std::this_thread::sleep_for(100ms);
std::cout << "Final refcount is " << bar::refcount << '\n';
}
|
I expect the the first will get to zero if the sleep in the second is added before printing the final refcount. The refcount waits for the observe_on to shutdown. |
There is a circular dependency here. I'll try to figure out how to resolve it myself I presume. It would be a good idea to run the tests with valgrind or sanitizers though, since a lot of issues are about memory leaks.
The text was updated successfully, but these errors were encountered: