Products

Price/Order

Support

Partners

Testimonials

Test Results

About us

Contact
 TRtcByteStream memory leak when preserving returned values
Bottom
 
Total posts: 10
 Author TRtcByteStream memory leak when preserving returned values
Johann Campbell

24.11.2007 19:40:08
Registered user
Hi, I am using a function created by the remote function wizard that is set to preserve the returned values. However, TRtcByteStream is the only object based value that causes a memory leak. TrtcDataSet, TrtcArray, TrtcRecord are all destroyed. So a code snippet that looks like this:

Stream := MyFunctions.GetFunction : TStream;
try
  // do something with the stream
finally
  Stream.Free;
end;

When the application is closed, there is a TRtcByteStream memory leak. This does not happen with other object values. This is also demonstrated in the BLOB Demo, adding FastMM4 to the uses clause of the client will yield a memory leak upon close.
Is anybody else seeing these issues with stream return values?

Thanks,

Johann
Danijel Tkalcec [RTC]

25.11.2007 00:13:09
Registered user
Hi Johann,

thank you for reporting this problem with the Remote Functions Wizard.

I have fixed this issue by adding the "Extract" method for all complex TRtcValueObject types for extracting the objects from their parent containers when using typed "as..." methods (ex: TStream from TRtcValue, by using asByteStream), and updated the Remote Functions Wizzard to use this new method when the "preserve return values" option is enabled.

The problem was that the Wizard gave you access to a TStream object held inside a TRtcByteStream container, but it did not free the TRtcByteStream container when you have selected the option to preserve returned values. If "preserve returned values" option was NOT used, there should have been no memory leaks.

Please download the new RTC SDK (v2.72) and the new RTC Remote Functions Wizzard (v1.1). This should fix the memory leak you have experienced. Should you experience any other problems or find any other memory leaks, please let me know.

Best Regards,
Danijel Tkalcec
Johann Campbell

25.11.2007 00:41:27
Registered user
If Delphi Informant Magazine was still around, RTC would be voted #1 for remoting components and if the support category existed, that too.

Thanks for the quick reply and the fix.

Keep up the excellent work.

Johann.
Danijel Tkalcec [RTC]

25.11.2007 02:13:34
Registered user
Wow! Thank you :-)

Regards,
Danijel
Chaiyaporn Suratemeekul

26.03.2008 12:48:45
Registered user
I 've same problem but in the server side

My function look like this


procedure TServerForm.RtcFunction1Execute(Sender: TRtcConnection;
  Param: TRtcFunctionInfo; Result: TRtcValue);
var
 
  OV:Variant;
  sql:string;
begin

  sql := param.asstring['sql'];
  

  Result.newByteStream;
 
  //.... Prepare OV Data  


  Result.AsByteStream:=VariantToStream(ov);
 



end;

each time this function get called by client it's never return memory
Danijel Tkalcec [RTC]

26.03.2008 13:02:42
Registered user
This is a different problem, but the problem is in your own code and the way you are using asByteStream assignments. If you look at the explanation of the "TRtcValue.asByteStream" method, you will see that the "asByteStream" assignment (write) will store a COPY of the original stream into the ByteStream contained in the TRtcValue object. It will NOT store a pointer to the original stream, nor will the original stream be destroyed.

In other words, by using this code ...
Result.AsByteStream := VariantToStream(ov);

... you are creating a new Stream object using the VariantToStream function, then copying only the content of that new Stream into "Result.asByteStream", but you are NOT destroying the original stream created by VariantToStream. And that - not destroying the original temporary stream created by VariantToStream - is generating your memory leak.

If you have a function which can write directly to a TStream, instead of creating a new TStream object, you should write directly into the stream contained in "Result.asByteStream" by doing something like ...
Other_VariantToStream(ov, Result.asByteStream);

... so that your data is directly written into the stream stored in the Result object and you do not have to separately manage another stream.

If you do NOT have a function which can write into a stream passed in as a parameter, but have to use the function VariantToStream which can only write into a stream which is created internally by the function and returned as a result, then you will have to implementat your remote functions like this ...
procedure TServerForm.RtcFunction1Execute(Sender: TRtcConnection;
  Param: TRtcFunctionInfo; Result: TRtcValue);
var
  OV:Variant;
  OVS:TStream; // Temporary stream
  sql:string;
begin
  sql := param.asstring['sql'];
 
  //.... Prepare OV Data  

  OVS := VariantToStream(ov); // create a stream from OV and remember the pointer
  Result.newByteStream; // create new ByteStream object in Result
  Result.AsByteStream:=OVS; // copy OVS content into the ByteStream
  OVS.Free; // Free the temporary stream
end;

This code will result in your data (variant) first being written into a new stream created by VariantToStream, then that data will be copied into Result's ByteStream, and then the temporary stream will be destroyed. That will resolve your memory leak problem.

Best Regards,
Danijel Tkalcec
Chaiyaporn Suratemeekul

26.03.2008 13:43:44
Registered user
Thank you very much.

Now memory leak is gone.
Johann Campbell

27.03.2008 00:01:23
Registered user
He could write directly to the stream if the OV Data could be converted to a string. It would save the overhead of creating and destroying a stream.


// convert OV Data to String - (Str)

Stream := Result.newByteStream;
Stream.Write(Str[1], Length(Str));


This will write the contents of the string directly to the stream and save the hassle of worrying about creating and destroying a separate stream.

Johann.
Danijel Tkalcec [RTC]

27.03.2008 09:20:27
Registered user
Thank you for the plug, Johann :)

Another thing to consider is that data available as a string can directly be assigned to "Result.asString" and read from "Result.asString" instead of going through a conversion to and from a ByteStream. In other words, the above code could be replaced with ...
// convert OV Data to String - (Str)
Result.asString:=Str; // Store the string in Result

Best Regards,
Danijel Tkalcec
Johann Campbell

27.03.2008 13:19:13
Registered user
Ahh! Correct you are. Just goes to show how versatile your components are.

Johann.