Pregunta

Heredé una aplicación Intraweb que tenía un archivo de texto de 2 MB de pérdidas de memoria según lo informado por FastMM4. Lo reduje a 115 instancias de una clase que pierde 52 bytes.

Una breve descripción del mal actor es:

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

y la interfaz es:

  ICwcCDSAdapterNav = interface(IInterface)  

¿Estoy ladrando el árbol equivocado, ya que la propiedad se cuenta como referencia? ¿Hay alguna circunstancia en la que la propiedad de la interfaz pueda evitar que se destruya la clase?

Aquí está la implementación del método anterior:

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 clase declarada como:

TCwcCDSAdapterNavBase = class(TInterfacedObject, ICwcCDSAdapterNav)
¿Fue útil?

Solución

FastMM debería darle lo que se filtró y dónde se creó.
Eso ayudaría a reducirlo al verdadero culpable: ¿quién está filtrando qué?

No estoy seguro de cuál es realmente tu pregunta.
Su código está incompleto o no es el que está en cuestión: su clase no tiene una propiedad de interfaz ni un campo privado de interfaz, solo un método que devuelve una interfaz, que es inofensivo.

Editar : sin ver el código de su Objeto implementando ICwcCDSAdapterNav, no podemos decir si realmente se cuenta con referencia.
Si no desciende de TInterfacedObject , es probable que no cuente con referencia y que no pueda confiar en esta liberación automática ...

Es posible que desee echar un vistazo a esta sesión de CodeRage 2 : Combatir las fugas de memoria para tontos . Principalmente muestra cómo usar FastMM para prevenir / detectar pérdidas de memoria en Delphi. Fue para D2007 pero sigue siendo relevante para otras versiones.

Otros consejos

Hasta ahora tienes buenas respuestas sobre cómo funciona FastMM. Pero en cuanto a su pregunta real, sí, los objetos interconectados pueden filtrarse de dos maneras diferentes.

  1. Las interfaces solo se cuentan por referencia si los objetos a los que pertenecen tienen un recuento de referencia implementado en sus métodos _AddRef y _Release. Algunos objetos no.
  2. Si tiene referencias de interfaz circular (la interfaz 1 hace referencia a la interfaz 2, que hace referencia a la interfaz 1), el recuento de referencias nunca caerá a 0 sin algunos trucos especiales de su parte. Si este es su problema, lo remitiré a la reciente publicación de blog sobre el tema de Andreas Hausladen.

Si está filtrando 115 instancias de esa clase, entonces es esa clase la que se está filtrando. La memoria ocupada por esa clase, no la memoria ocupada por las cosas a las que se refiere, se está filtrando. En algún lugar, tiene 115 instancias de TCwcBasicAdapter que no está liberando.

Además, las propiedades no almacenan datos, sin importar si son interfaces u otro tipo. Solo los campos ocupan memoria (junto con algún espacio oculto que el compilador asigna en nombre de la clase).

Entonces, sí, estás ladrando el árbol equivocado. Su pérdida de memoria está en otro lugar. Cuando FastMM le dice que tiene una pérdida de memoria, ¿no le dice también dónde se asignó cada instancia filtrada? Tiene esa capacidad; es posible que deba ajustar algunos símbolos de compilación condicional para habilitar esa función.

Sin embargo,

seguramente no son solo instancias de esa clase las que están goteando. FastMM también debe informar algunas otras fugas, como instancias de la clase o clases que implementan la interfaz.


Basado en la función que agregaste, he comenzado a sospechar que realmente se está filtrando TCwcCDSAdapterNavBase , y eso podría deberse a la forma atípica que usas para crearlo. ¿Se ejecuta alguna vez el controlador de excepciones en GetAdapterNav ? Lo dudo; TObject.GetInterface nunca plantea explícitamente una excepción. Si el objeto no admite la interfaz, devuelve False . Todo lo que el controlador de excepciones podría detectar son cosas como la infracción de acceso y las operaciones ilegales, que realmente no deberías detectar allí de todos modos.

Puede implementar esa función más directamente así:

if Assigned(FDataSet) then
  Result := TCwcCDSAdapterNavBase.Create(...);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top