TLDR: metodele sunt
cod, nu ocupă memorie pe fiecare
obiect.
În memorie, metodele sunt asociate unei
clase, nu unui
obiect. La instanțiere,
obiectul în memorie conține doar
membrii (variabile, de fapt pointeri către alte obiecte) + un pointer către clasă/tip (și clasa în sine are o reprezentare obiectuală, uzual una singură per runtime/classloader). Când apelezi o metodă pe un obiect, runtime-ul ia obiectul, verifică în clasa asociată că există metoda respectivă cu semnătura utilizată, și apelează acea metodă (pointer către bytecode + pointer către obiect + parametrii metodeir). De instanțierea obiectelor
clasă se ocupă VM-ul (CLR, JVM, etc) și uzual doar când sunt folosite (ca să nu ocupe memorie degeaba).
Uzual se "trișează" pentru primitive. C# definește de fapt
int ca
System.Int32, care e o
structură, și nu o
clasă. De fapt int-ul tău va consuma tot 4 octeți, dar
undeva trebuie să se menționeze că acolo e un int și că mai are niște metode - aici depinde de runtime și optimizările sale; probabil nu poți să ajungi
chiar ca în C, unde ai o adresă de memorie și e problema ta cum o folosești (între timp s-au mai implementat idei de securitate și GC), dar trebuie să fie foarte aproape, pentru optimizarea resurselor.
Pentru o înțelegere mai bună vezi
Reflection, care îți permite accesul la implementare în timpul rulării. Vezi și
Duck typing și
Strong/weak typing.