delphifastmmremobjects

Delphi releases interface too soon


I've a Delphi client/server project, which uses RemObjects for communication between client and server. In remobject the server and public service functions are defined and interfaces are generated for it. At some points, we need to call other services, from withith another service. In order to do this, we created class methods/functions, pass over the current database connection and remobjects session, an call an implementation of the desired function. For example:

class function TMyService.GetFoo(session: TROSession; conn: Connection): AnsiString;
var
    svc: TMyService;
begin
    svc := TMyService.Create(nil);
    try
      IROObjectActivation(svc).OnActivate(session.SessionID, nil);
      try
        Result := svc.GetFooImpl();
      finally
        IROObjectActivation(svc).OnDeactivation(session.SessionID);
      end;
    finally
      FreeAndNil(svc);
    end;
end;

Some times, looks random, svc seems already to be free'd, before the FreeAndNil call, which causes access violations.

At this point, TMyService, also has a generated interface IMyService, but this only contians the public methods, not the implementations. That's why we use the type instead of the interface to devince the svc variable.

As far as I know, interfaced objects should be free'd at the end of a method, and not half way. Are there any compiler optimisations which can affect this behaviour?

[edit] By the way, FastMM4 is also compiled in this project, which may have some effect on this. Project compiled with Delphi 10.3


Solution

  • If TMyService supports interfaces, and you have problems with premature releasing, that means TMyService class is reference counted class (in other words, it supports interfaces, but reference counting is not disabled).

    In such cases you need to store such object instance in interface reference to properly initialize reference counting. Also you should not manually release such object because its memory will be automatically managed, and if you need to access some methods that are not exposed through interface you can do that by typecasting.

    However, using methods that are not exposed through interface is potential abuse of the class. Usually, interfaces contain all methods that are meant to be used.

    class function TMyService.GetFoo(session: TROSession; conn: Connection): AnsiString;
    var
        svc: IMyService;
    begin
        svc := TMyService.Create(nil);
        IROObjectActivation(svc).OnActivate(session.SessionID, nil);
        try
          Result := svc.GetFooImpl();
          // or
          Result := TMyService(svc).GetFooImpl();
        finally
          IROObjectActivation(svc).OnDeactivation(session.SessionID);
        end;
    end;
    

    Whether or not you will need to use typecast for IROObjectActivation depends on the declaration of IMyService. Possibly, you don't need IMyService interface and you can just use IROObjectActivation.