vpmeister has asked for the wisdom of the Perl Monks concerning the following question:

I am calling a routine that requires a ByRef array as one of the arguments. The routine modifies the array values for the caller. I can create a Variant(VT_ARRAY|VT_I4|VT_BYREF, ...) and send that to the subroutine. I get the data back just fine, but because the Variant has the VT_BYREF attribute, the SAFEARRAY it points to is not cleaned up when the variable goes out of scope. I am using Win::OLE version 0.1712. See the following code:
# OLE Variant memory test use strict; use Win32::OLE::Variant; for my $i ( 0 .. 10000 ) { my $v = Win32::OLE::Variant->new(VT_ARRAY|VT_BSTR|VT_BYREF, [1,1000] +); DoStuff(\$v); undef $v; } print STDERR "Waiting..."; # give time to watch process in Windoze Tas +k Mangler sleep(5); print STDERR "Done.\n"; sub DoStuff { my $refVar = shift; # reference to the Variant for my $i ( 1 .. 1000 ) { $$refVar->Put($i, "Fred and barney are funny $i"); } }
If the Variant is created without the VT_BYREF then it is cleaned up properly and there is no leak. I think what should happen is that $v should be created without the VT_BYREF, and then I create a new Variant, $vr, which has the VT_BYREF attribute and points to the data in $v. Then i can pass $vr to the DoStuff(). DoStuff modifies the values, which are really also the values in $v. Then when it comes time to clean up, the array data in $vr is not released, but it is in $v. So the question is: How do I do something like: my $vr = $v; such that $vr now has the VT_BYREF attribute and points to the same data in $v? Here is the latest test code I am working with:
# OLE Variant memory test use strict; use Win32::OLE::Variant; for my $i ( 0 .. 0 ) { my $v = Win32::OLE::Variant->new(VT_ARRAY|VT_BSTR, [1,1000]); $v->Put(1, "not changed"); # Do something here to make $vr a separate variant that points to th +e data in $v my $vr = Win32::OLE::Variant->new(VT_ARRAY|VT_BSTR|VT_BYREF, $v); DoStuff(\$vr); # modify $vr and see if $v has changed printf "0x%04x, %s; 0x%04x, %s\n", $v->_RefType(), $v->Get(1), $vr-> +_RefType(), $vr->Get(1); undef $v; } print STDERR "Waiting..."; # give time to watch process in Windoze Tas +k Mangler sleep(5); print STDERR "Done.\n"; sub DoStuff { my $refVar = shift; # reference to the Variant for my $i ( 1 .. 1000 ) { $$refVar->Put($i, "Fred and barney are funny $i"); } }

Replies are listed 'Best First'.
Re: Avoiding Memory Leaks with Win32::OLE (what leaks)
by Anonymous Monk on Oct 17, 2015 at 00:13 UTC

    What do you see in taskmanager that tells you there is a memory leak?

    On my system the memory is remains below 5mb

    I added use warnings; and I keep getting

    Use of uninitialized value in subroutine entry at win32-ole-variant-me +mleak-1145019.pl line 11. Use of uninitialized value in printf at win32-ole-variant-memleak-1145 +019.pl line 13.
      Memory usage grows roughly rapidly and monotonically. Since the original post, I have modified the Win32::OLE module on my machine to also delete the SAFEARRAY associated with Variants that have the VT_ARRAY and VT_BYREF flags set. Of course this contravenes the appropriate usage of the VT_BYREF, but when I use that module with this code, the memory usage is stable.

      So it seems to me that it is possible to create a variant with the VT_BYREF flag that is the actual owner of the data. This should not be the case, as the whole idea of the VT_BYREF is that some other data structure owns the data and will take care of its cleanup

        Memory usage grows roughly rapidly and monotonically.

        Can you put some numbers on this?

        Since the original post, I have modified the Win32::OLE module on my machine to also delete the SAFEARRAY associated with Variants that have the VT_ARRAY and VT_BYREF flags set.

        How, what did you do?

        So it seems to me that it is possible to create a variant with the VT_BYREF flag that is the actual owner of the data. This should not be the case, as the whole idea of the VT_BYREF is that some other data structure owns the data and will take care of its cleanup

        maybe all thats needed is to expose API to "cleanup" this data as well, for the people who manage to create one of these things?

      Thanks for the test with use warnings; I should do that more often. I tried the use warnings; and reproduced the problem. The following code fixes that issue. And it also has the proper behavior of the $v variable being changed by the subroutine. That is good. But it still leaks memory. That is bad. Now at about 1000k/second.

      Also you will see that the flags showing the type of the $vr varible no longer have the VT_BYREF flag (that would be 0x6...)

      # OLE Variant memory test use strict; use warnings; use Win32::OLE::Variant; for my $i ( 0 .. 10000 ) { my $v = Win32::OLE::Variant->new(VT_ARRAY|VT_BSTR, [1,1000]); $v->Put(1, "not changed"); # Do something here to make $vr a separate variant that points to th +e data in $v my $vr = Win32::OLE::Variant->new(VT_ARRAY|VT_BSTR|VT_BYREF, [1,1000 +]); $vr = $v; DoStuff(\$vr); # modify $vr and see if $v has changed printf "0x%04x, %s; 0x%04x, %s\n", $v->_RefType(), $v->Get(1), $vr-> +_RefType(), $vr->Get(1); undef $v; } print STDERR "Waiting..."; # give time to watch process in Windoze Tas +k Mangler sleep(5); print STDERR "Done.\n"; sub DoStuff { my $refVar = shift; # reference to the Variant for my $i ( 1 .. 1000 ) { $$refVar->Put($i, "Fred and barney are funny $i"); } }
      But I still like the proposed ByRef() method to make a variable that points to another one. (See responses to the Re^3 reply to this post.)
Re: Avoiding Memory Leaks with Win32::OLE
by u65 (Chaplain) on Oct 16, 2015 at 22:53 UTC

    Welcome, vpmeister. I'm sorry I can't help (I don't use Perl on Windows), but have you tried to contact the author of the module? Have you filed a bug, or is there an existing issue similar to the one you are experiencing (I see there are 22 new or open bugs listed on CPAN)?