metodi di istanza, stack o heap

3

I metodi (e le loro variabili) che appartengono a un'istanza di oggetto vanno nello stack o nell'heap?

Ex

Main()
{
Myclass Myobj = new Myclass();
Myobj.Doit();
}

class Myclass
{
 Void Doit()
 {
 Int myint = 5;
 }
}

Uso principalmente c #, ma presumo che la risposta sia indipendente dal linguaggio.

    
posta WZRh1jq91 22.10.2014 - 03:41
fonte

3 risposte

11

Lo standard CLR non richiede uno stack o un heap, quindi prima lasciamolo fuori. Ma C # implementato su carta non è molto utile. Descrivo qui le implementazioni che possiamo eseguire con "in pratica" il codice, come Microsoft C # o Mono C #. Indipendentemente da ciò, il metodo e le variabili locali hanno una relazione concettuale con le classi e le istanze dell'oggetto che devi capire, perché non è specifico di C #, è lo stesso per i linguaggi del computer in generale.

I metodi di istanza sono memorizzati nello stesso modo in cui sono usati i metodi statici.

I metodi fanno parte di code (in CLR, bytecode), sono istruzioni compilate, codici opzionali CLR di basso livello che costituiscono l'assembly. Quindi nel modello C # non fanno parte di un heap, l'heap è per data . ( Vedi nota a fondo nota ). Nelle lingue che non sono orientate agli oggetti, ci sono semplici funzioni. In quelle lingue, le funzioni sono solo codice che riceve argomenti. In CLR una funzione semplice è un metodo statico (o metodo di classe). L'unica differenza in una funzione e in un metodo è che lo zucchero sintattico fa sembrare che la funzione sia di proprietà, ma il suo oggetto è in realtà solo il primo argomento "implicito" (this), e nella maggior parte dei linguaggi viene prima della chiamata al metodo, es. %codice%. Il primo argomento della funzione deve ancora essere caricato da un'istruzione; in CLIL MSIL, obj.Foo() viene caricato da this tranne nel caso di un metodo statico. Quindi ldarg.0 equivale a obj.Foo(arg) .

Quando compilate una classe, il compilatore emette un set di istruzioni che rappresentano il metodo e lo impacchetta in un segmento di codice.

La relazione del metodo con l'oggetto è in realtà simile alla relazione tra classe e oggetto. Il metodo è parte della classe (cioè parte del tipo , non parte dell'oggetto. Il metodo è simile a dati statici , ma i "dati metodo" capita Come i campi statici, i metodi esistono prima e senza alcuna esistenza di un'istanza di oggetto e sono solo una parte del tipo di oggetto. Potrei avere 1.000.000 di istanze di una stringa, ma c'è una singola copia di Foo(obj,arg) da qualche parte.

Per quanto riguarda le variabili locali di un metodo, non esistono finché non viene chiamato il metodo. All'inizio di un metodo CLR, il frame di chiamata assicura spazio per tutte le variabili locali in quel metodo. Sono noti in anticipo, ma sono semplicemente notazione formale fino all'esecuzione del metodo, quindi diventano indirizzi di dati reali . Un'istruzione dice al CLR quanto spazio dedicare. I valori delle variabili locali sono concettualmente e praticamente in pila, ma mappati ai registri. Le variabili sono "locali" rispetto all'ambito del metodo e si allontanano quando il metodo restituisce (sebbene gli oggetti a cui si riferiscono possano non esserlo). Ci sono istruzioni per gestirli in CLR. Analizziamo un campione approssimativo di MSIL (assembly IL per CLR) per il tuo metodo string::Concat(string) .

.method void MyClass::Doit()
{
    .locals init([0]int myint)   // declares the locals for the method
    ldc.i4.5
    stloc 'myint'                // initialize myint to 0
    ret
}

I locals sono mappati in maniera aggressiva ai registri della CPU reali dal compilatore JIT in modo che esistano principalmente su uno stack quando CLR sta interpretando o verificando il bytecode. In pratica, i locals esistono nei registri, ma si riversano su una pila nell'hardware di basso livello.

Infine, per qualsiasi linguaggio del computer, ci sono 3 gruppi principali di sintassi.

  1. Digitare dichiarazioni e definizioni (idee formali, regole di compilazione e metadati)
  2. Algorithmic (codice, metodi, istruzioni, espressioni)
  3. Dati e variabili (dati)

Attenzione: i sistemi Runtime sono comunemente implementati in C o C ++. Un assembly CLR e i relativi metodi vengono caricati nell'heap di runtime della lingua host utilizzata per scrivere il CLR. Ma concettualmente si tratta di un heap diverso da "heap" a cui si sta accedendo all'interno del CLR.

    
risposta data 22.10.2014 - 04:36
fonte
3

In generale, il codice del programma esiste in un'area al di fuori di ciò che intendi quando dici "stack" e "heap". Mentre hai citato C #, non ci sono tag di linguaggio quindi descriverò come un tipico desktop OS moderno lo gestisce a un livello basso.

Quando viene caricato il programma, ci sono due aree principali di memoria: codice e dati. Il sistema operativo alloca memoria sufficiente per caricare il programma, che contiene il codice eseguibile, i dati statici (ad esempio costanti) e qualsiasi codice di bootstrap incluso nel compilatore (qualcosa deve chiamare main ).

In questo senso il codice è in un heap, semplicemente perché tutto è heap assegnato dalla prospettiva del sistema operativo. Tuttavia, dal punto di vista del tuo programma, è fuori dall'heap dello stack e del programma. Non è possibile allocare memoria in entrambe le posizioni e inserire il codice, in genere (eccezione: paragrafo successivo).

Alcune lingue consentono chiamate eval o exec in cui una variabile viene eseguita come codice, che potrebbe includere una funzione e una chiamata a tale funzione. In questo senso il codice potrebbe esistere nello stack o nell'heap, anche se i dettagli vengono estratti per la maggior parte del tempo in lingue che lo consentono (ad esempio Perl o PHP). È difficile non sapere con certezza dove si trova il codice in questo caso.

Questa separazione del codice dal segmento dei dati (e quindi dall'heap e dallo stack) sta diventando sempre più strong man mano che le nuove CPU hanno il supporto a livello hardware per vietare l'esecuzione del codice dal segmento di dati. L'idea è quella di aiutare a neutralizzare i virus che dipendono da quello per modificare il codice in esecuzione e quindi per diffondere ed eludere il rilevamento. Se un programma è soggetto alla protezione del flag di esecuzione, il codice non può essere eseguito dalla parte di memoria di dati (stack e heap).

    
risposta data 22.10.2014 - 04:22
fonte
0

In C # la gestione della memoria è un dettaglio di implementazione. Non c'è alcuna garanzia su dove andranno i tuoi oggetti.

Non esiste nemmeno la garanzia che esista uno "stack" nel sistema operativo che lo esegue.

Non basare alcuna logica su di esso.

L'articolo di cui ho le mie conoscenze:

link

    
risposta data 22.10.2014 - 03:51
fonte

Leggi altre domande sui tag