locked
Memory leaks with lambda expressions

    Question

  • Hello, I have the following code where I'm capturing a variable (test) which is an instance to a ref class.

    ThreadPool::RunAsync(ref new WorkItemHandler([test](Windows::Foundation::IAsyncAction^ operation) { ... }))->Start();

    C++ variables captured in this way are copied. I assume the instances of ref classes are just retained (using AddRef internally). The problem is that the instance isn't disposed when the lambda expression is destroyed. My understanding is that the instance of WorkItemHandler should be destroyed when the async operation is finished along with the lambda expression which should release all variables that are not captured by reference.

    Is this a bug in the preview version of the compiler or am I doing something wrong?


    • Edited by Atamiri Monday, October 31, 2011 10:17 PM
    Friday, October 28, 2011 4:56 PM

Answers

All replies

  • Your expectations are correct, but we can't reproduce the behavior you are seeing with just the minimal snippet above. Can you provide a complete, minimal repro? What are you observing that leads you to believe there's a missing release call? I ask because it's also possible that some other component wiring is broken, instead.

     

    Thanks,

     

    Ben Kuhn

    Monday, October 31, 2011 9:13 PM
  • Hi Ben, thank you for looking at my problem. In the code below the destructor of Test isn't called. It's called if I use [&] instead of [=].

     

    ref class Test {
    public:
    	~Test() { OutputDebugStringW(L"Disposed\n"); }
    	void Dummy() { OutputDebugStringW(L"Dummy\n"); }
    };
    
    delegate void MyDelegate();
    
    [Platform::MTAThread]
    int main(array<Platform::String^>^) {
    	{
    		auto test = ref new Test();
    		auto lmbd = [=](){ test->Dummy(); };
    		auto dlgt = ref new MyDelegate(lmbd);
    	}
    	OutputDebugStringW(L"End\n");
    }
    
    Monday, October 31, 2011 10:25 PM
  • I can repro the OP's problem using similar code. The introduction of a lambda seems to prevent the destructor from being called. (not a problem when you capture by &)


    http://blog.voidnish.com
    Wednesday, November 02, 2011 2:51 PM
  • When you capture by value there is one Release() missing. I wonder if this may be due to a bug in attempting to optimize away a AddRef/Release when it's determined to not be required.
    http://blog.voidnish.com
    Wednesday, November 02, 2011 3:08 PM
  • Possibly. I've sent this over to the compiler team to have someone take a look. I'll post back here as soon as I get a response.

     

    Thanks,

     

    Ben Kuhn

    Wednesday, November 02, 2011 4:59 PM
  • @Atamiri

    As there is some investigation required for this, would you mind filing a bug for this issue?

    Thanks,
    -David

    Bug filing form for VS11 is here:
    http://connect.microsoft.com/visualstudio/

    Thursday, November 03, 2011 6:55 PM
    Moderator
  • Hi David, OK, I'll file a bug.

    Thank you

    Thursday, November 03, 2011 10:57 PM
  • Hi David, OK, I'll file a bug.

    Thank you


    Please post the link here when you do so, so others can vote it up.
    http://blog.voidnish.com
    Friday, November 04, 2011 2:55 PM
  • Following up, I couldn't find a bug yet so I created one located here:

    https://connect.microsoft.com/VisualStudio/feedback/details/704624/memory-leaks-with-lambda-expressions

    Wednesday, November 16, 2011 7:48 PM
    Moderator