Domanda

Ho ereditato un'app Intraweb che aveva un file di testo da 2 MB di perdite di memoria come riportato da FastMM4. Sono arrivato a 115 istanze di una classe che perde 52 byte.

Una breve descrizione del cattivo attore è:

TCwcBasicAdapter = class(TCwcCustomAdapter)  
  protected  
    FNavTitleField: TField;  
    function GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav; override;  
  public  
    constructor Create(aDataSource: TDataSource; aKeyField, aNavTitleField: TField; aMultiple: boolean);  
  end;  

e l'interfaccia è:

  ICwcCDSAdapterNav = interface(IInterface)  

Sto abbaiando sull'albero sbagliato, poiché la proprietà viene contata come riferimento? Vi sono circostanze in cui la proprietà dell'interfaccia potrebbe impedire la distruzione della classe?

Ecco l'implementazione del metodo sopra:

function TCwcBasicAdapter.GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav;
var
  AdapterNav: TCwcCDSAdapterNavBase;
begin
  result := nil;
  if Assigned(aDataSet) then begin
    AdapterNav := TCwcCDSAdapterNavBasic.Create(aDataSet, FKeyField.Index, FNavTitleField.Index);
    try
      AdapterNav.GetInterface(ICwcCDSAdapterNav, result);
    except
      FreeAndNil(AdapterNav);
      raise;
    end;
  end;
end;

con la classe dichiarata come:

TCwcCDSAdapterNavBase = class(TInterfacedObject, ICwcCDSAdapterNav)
È stato utile?

Soluzione

FastMM dovrebbe fornirti ciò che è trapelato e dove è stato creato.
Ciò contribuirebbe a restringerlo al vero colpevole: chi perde cosa?

Non sono sicuro di quale sia davvero la tua domanda?
Il tuo codice è incompleto o non quello in questione: la tua classe non ha una proprietà Interface né un campo privato Interface, solo un metodo che restituisce un'interfaccia, che è innocua.

Modifica : senza vedere il codice del tuo oggetto che implementa ICwcCDSAdapterNav, non possiamo dire se è effettivamente contato come riferimento.
Se non discendi da TInterfacedObject , è probabile che non sia conteggiato il riferimento e che non puoi fare affidamento su questa liberazione automatica ...

Potresti dare un'occhiata a questa sessione CodeRage 2 : Combattere le perdite di memoria per i manichini . Mostra principalmente come utilizzare FastMM per prevenire / rilevare perdite di memoria in Delphi. Era per D2007 ma è ancora rilevante per altre versioni.

Altri suggerimenti

Finora hai ottenuto delle buone risposte su come funziona FastMM. Ma per quanto riguarda la tua vera domanda, sì, gli oggetti interfacciati possono fuoriuscire in due modi diversi.

  1. Le interfacce vengono contate per riferimento solo se gli oggetti a cui appartengono hanno implementato il conteggio dei riferimenti nei loro metodi _AddRef e _Release. Alcuni oggetti no.
  2. Se si hanno riferimenti all'interfaccia circolare, (L'interfaccia 1 fa riferimento all'interfaccia 2, che fa riferimento all'interfaccia 1), il conteggio dei riferimenti non scenderà mai a 0 senza alcuni trucchi speciali da parte dell'utente. Se questo è il tuo problema, ti rimando al post recente sul blog di Andreas Hausladen.

Se stai perdendo 115 istanze di quella classe, allora è quella classe ad essere trapelata. La memoria occupata da quella classe, non la memoria occupata dalle cose a cui si riferisce, viene fatta trapelare. Da qualche parte, hai 115 istanze di TCwcBasicAdapter che non stai liberando.

Inoltre, proprietà non memorizza i dati, non importa che siano interfacce o altri tipi. Solo i campi occupano memoria (insieme allo spazio nascosto allocato dal compilatore per conto della classe).

Quindi sì, stai abbaiando sull'albero sbagliato. La tua perdita di memoria è altrove. Quando FastMM ti dice che hai una perdita di memoria, non ti dice anche dove è stata allocata ogni istanza trapelata. Ha quella capacità; potrebbe essere necessario modificare alcuni simboli di compilazione condizionale per abilitare quella funzione.

Sicuramente però non sono solo le istanze di quella classe che perdono. FastMM dovrebbe inoltre segnalare altre perdite, ad esempio istanze della classe o delle classi che implementano l'interfaccia.


In base alla funzione che hai aggiunto, ho iniziato a sospettare che sia davvero TCwcCDSAdapterNavBase a perdere, e ciò potrebbe essere dovuto al modo atipico che usi per crearlo. Il gestore delle eccezioni in GetAdapterNav non viene mai eseguito? Ne dubito; TObject.GetInterface non solleva mai esplicitamente un'eccezione. Se l'oggetto non supporta l'interfaccia, restituisce False . Tutto ciò che il gestore delle eccezioni potrebbe cogliere sono cose come la violazione dell'accesso e le operazioni illegali, che in realtà non dovresti essere lì a catturare.

Puoi implementare questa funzione più direttamente in questo modo:

if Assigned(FDataSet) then
  Result := TCwcCDSAdapterNavBase.Create(...);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top