2009-03-24 10 views
7

TObject.InstanceSize restituisce 8, ma TObject non dichiara alcun membro dati. Secondo l'implementazione di TObject.ClassType, i primi 4 byte possono essere spiegati come un puntatore ai metadati TClass dell'oggetto. Qualcuno sa a cosa servono gli altri 4 byte di overhead?Quali dati contiene un TObject?

MODIFICA: Apparentemente questo è specifico per D2009. Nelle versioni precedenti, è solo 4 byte.

risposta

11

In Delphi 2009, c'è the ability to have a reference to a synchronization monitor. Vedi:

class function TMonitor.GetFieldAddress(AObject: TObject): PPMonitor; 
class function TMonitor.GetMonitor(AObject: TObject): PMonitor; 

... in System.pas

Inoltre, c'è ancora un puntatore al VMT. (Metodo tabella virtuale.) From Delphi in a Nutshell:

La classe TObject dichiara diversi metodi e uno speciale, campo nascosto per memorizzare un riferimento alla classe dell'oggetto . Questo campo nascosto fa riferimento alla tabella dei metodi virtuali della classe (VMT). Ogni classe ha un VMT univoco e tutti gli oggetti di quella classe condividono il VMT della classe .

+0

Questa è la stessa cosa, in realtà. Il riferimento TClass di una classe punta al suo VMT. Quindi sono gli stessi 4 byte. Quali sono gli altri 4? –

+0

(Vale la pena notare che quel libro è stato scritto 9 anni fa.Forse all'epoca esisteva solo un campo nascosto. Ora sembra che ce ne siano due.) –

+0

C'è anche un monitor di sincronizzazione in D2009. Aggiornerò –

3

Un oggetto contiene voci per tutti i suoi campi, oltre a uno spazio aggiuntivo per contenere un puntatore alla tabella del metodo virtuale. Il VMT contiene più di semplici puntatori del metodo virtuale. Spiego more about the VMT sul mio sito Web, incluso un diagramma.

Apparentemente, Delphi 2009 introduce un altro campo nascosto oltre al puntatore VMT per contenere il monitor di sincronizzazione. È possibile determinare se si è aggiunto all'inizio o alla fine della classe con un codice semplice:

type 
    TTest = class 
    FField: Integer; 
    end; 

var 
    obj: TTest; 
    ObjAddr, FieldAddr: Cardinal; 
begin 
    Assert(TTest.InstanceSize = 12); 
    obj := TTest.Create; 
    ObjAddr := Cardinal(obj); 
    FieldAddr := Cardinal(@(obj.FField)); 
    writeln(FieldAddr - ObjAddr); 
end. 

Se si stampa il valore 4, il campo monitor deve essere alla fine l'oggetto a causa 4 conta solo per la dimensione del puntatore VMT. Se stampa il valore 8, il campo del monitor deve essere all'inizio, adiacente al puntatore del VMT.

Mi aspetto che troverai il monitor all'inizio. Altrimenti, significa che il layout dell'oggetto discendente non è semplicemente il layout dell'oggetto base con tutti i nuovi campi aggiunti. Significa che l'offset del campo del monitor dipende dal tipo di runtime dell'oggetto e ciò rende l'implementazione più complicata.

Quando una classe implementa un'interfaccia, il layout dell'oggetto include più campi nascosti. I campi contengono puntatori al valore di riferimento dell'interfaccia dell'oggetto. Quando si dispone di un riferimento IUnknown a un oggetto, il puntatore che contiene non è lo stesso del puntatore al campo VMT dell'oggetto, che è ciò che si ha con un riferimento di oggetto ordinario. Il valore del puntatore IUnknown sarà l'indirizzo del campo nascosto. Ho scritto more about the layout of classes that implement interfaces.

+0

No. GetInterfaceTable è una funzione di classe basata su un offset dalla posizione VMT. Dai un'occhiata all'implementazione di TMonitor.GetFieldAddress. Sembra che dipenda dal tipo di runtime, esattamente come hai descritto. –

+0

GetInterfaceTable recupera qualcosa di diverso, separato dal riferimento all'interfaccia. La tabella di interfaccia è condivisa da tutte le istanze di una classe, proprio come il VMT. Il riferimento all'interfaccia non è condiviso da altre istanze. Leggi il mio articolo per ulteriori informazioni sul layout delle classi interfacciate. –

+0

Non riesco a controllare la fonte per TMonitor.GetFieldAddress; Non ho Delphi 2009. –

Problemi correlati