Velikost pole objektů v Go

Golanger

Velikost pole objektů v Go
« kdy: 21. 03. 2018, 02:33:27 »
Mám proměnnou typu
Kód: [Vybrat]
[10]Worker a dávám do ní ukazatele na
Kód: [Vybrat]
type Calculon struct Velikost pole na amd64 je ale 160 bajtů, máte někdo vysvětlení, proč to není 80? (Velikost pointru by snad měla být 8 bajtů.)


klokan

Re:Velikost pole objektů v Go
« Odpověď #1 kdy: 21. 03. 2018, 04:16:42 »
Neznám Go tak dalece, ale je možné, že to je podobné, jako v Rustu. Tam jsou některé ukazatele dvakrát delší, než nativní délka pointeru, protože kromě samotné adresy obsahují taky jakýsi identifikátor typu objektu (u traitů v Rustu např pointer na ekvivalent v-table). Takže když budu mít pole typu [&Krava; 10] a Krava je trait, tak to bude taky celkem 160 bajtů.

Podle tvého příkladu to vypadá, že Worker je asi interface a Calculon bude objekt, který podporuje Worker, takže to je stejná situace. Je tedy dost možné, že na to Go používá podobný mechanismus, tj. každý pointer jsou vlastně dva: jeden na samotný objekt Calculon, a jeden na vtable Worker pro Calculon.

Možná to ale tak vůbec není a některý z místních expertů na Go mě vyvede z omylu.

heeeerecka

Re:Velikost pole objektů v Go
« Odpověď #2 kdy: 21. 03. 2018, 05:36:57 »
A divas se na velikost pole nebo jeho kapacitu

Jester

Re:Velikost pole objektů v Go
« Odpověď #3 kdy: 21. 03. 2018, 07:52:42 »
A divas se na velikost pole nebo jeho kapacitu
Ach jo. Pole nemá kapacitu, tohle není slice.

ava

Re:Velikost pole objektů v Go
« Odpověď #4 kdy: 21. 03. 2018, 09:03:12 »
Neznám Go tak dalece, ale je možné, že to je podobné, jako v Rustu. Tam jsou některé ukazatele dvakrát delší, než nativní délka pointeru, protože kromě samotné adresy obsahují taky jakýsi identifikátor typu objektu (u traitů v Rustu např pointer na ekvivalent v-table). Takže když budu mít pole typu [&Krava; 10] a Krava je trait, tak to bude taky celkem 160 bajtů.

Podle tvého příkladu to vypadá, že Worker je asi interface a Calculon bude objekt, který podporuje Worker, takže to je stejná situace. Je tedy dost možné, že na to Go používá podobný mechanismus, tj. každý pointer jsou vlastně dva: jeden na samotný objekt Calculon, a jeden na vtable Worker pro Calculon.

Možná to ale tak vůbec není a některý z místních expertů na Go mě vyvede z omylu.

Souhlasím se vším, jen drobné doplnění - ty "dvakrát větší ukazatele" se v Rustu nejmenují ukazatele ale Trait Objects. To, že syntaxe pro trait object začíná & takže se tváří jako obyčejná reference (pointer) je spíš matoucí a autoři to chtějí změnit: https://github.com/rust-lang/rfcs/blob/master/text/2113-dyn-trait-syntax.md . Ukazatel na trait object už má velikost normální:

trait T {}
println!("{}, {}", mem::size_of::<&T>(), mem::size_of::<&&T>());
16, 8

Jinak bych to napsal stejně, taky Go neznám a taky bych podezříval že tohle bude ta příčina :)


Golanger

Re:Velikost pole objektů v Go
« Odpověď #5 kdy: 21. 03. 2018, 09:42:55 »
Je to kvůli polymorfismu, proměnná typu rozhraní si nese navíc odkaz na konkrétní typ. Překladač to různě agresivně optimalizuje, ale při uložení do kolekce se to projeví.

.

Re:Velikost pole objektů v Go
« Odpověď #6 kdy: 21. 03. 2018, 09:55:20 »
Tohle je zvláštní, můžeš dát odkaz na kus kódu, ne jen ty dva řádky? Jak jsi měřil velikost? Odhaduji, že tam někde máš interface.

Posílám příklad: https://play.golang.org/p/csFOH8bquZG

výstup na play (64 bitů s 32 bit pointry):
Kód: [Vybrat]
amd64p32
4
8
4
4
40
40
80
40

výstup na amd64:
Kód: [Vybrat]
amd64
8
16
8
8
80
80
160
80

.

Re:Velikost pole objektů v Go
« Odpověď #7 kdy: 21. 03. 2018, 09:57:24 »
Než jsem to celé dopsal, tak jsi to sám poslal. :)

Jester

Re:Velikost pole objektů v Go
« Odpověď #8 kdy: 21. 03. 2018, 12:05:43 »
Jak jsi měřil velikost?
Jinak než přes unsafe.Sizeof to nejde.

.

Re:Velikost pole objektů v Go
« Odpověď #9 kdy: 21. 03. 2018, 15:52:20 »
Jak jsi měřil velikost?
Jinak než přes unsafe.Sizeof to nejde.
Já bych to takhle neřešil, ale umím si představit zjišťování přes velikost alokované paměti v runtime nebo přes volbu b.ReportAllocs().

klokan

Re:Velikost pole objektů v Go
« Odpověď #10 kdy: 22. 03. 2018, 00:18:11 »
Jinak bych to napsal stejně, taky Go neznám a taky bych podezříval že tohle bude ta příčina :)

Udělal jsem malý pokus: podobný příklad jako autorův jsem prohnal zkrk gccgo a podíval se do GIMPLE. Reference na Worker je skutečně struktura obsahující dva pointery: __methods a __object, neboli celkem 128 bitů.

Poučení je jasné: reference není totéž, co pointer! Člověk zvyklý na C++ si většinou myslí, že to je jenom jiná syntaxe pro stejnou konstrukci, ale v těchto novějších jazycích tomu tak už není.

Jester

Re:Velikost pole objektů v Go
« Odpověď #11 kdy: 22. 03. 2018, 00:59:29 »
Jinak bych to napsal stejně, taky Go neznám a taky bych podezříval že tohle bude ta příčina :)

Udělal jsem malý pokus: podobný příklad jako autorův jsem prohnal zkrk gccgo a podíval se do GIMPLE. Reference na Worker je skutečně struktura obsahující dva pointery: __methods a __object, neboli celkem 128 bitů.

Poučení je jasné: reference není totéž, co pointer! Člověk zvyklý na C++ si většinou myslí, že to je jenom jiná syntaxe pro stejnou konstrukci, ale v těchto novějších jazycích tomu tak už není.
To už nejsou reference, tady jde o rozdíl mezi konkrétními typy a rozhraními (což je dynamický odkaz umožňující kachní polymorfismus).

klokan

Re:Velikost pole objektů v Go
« Odpověď #12 kdy: 22. 03. 2018, 02:53:50 »
To už nejsou reference, tady jde o rozdíl mezi konkrétními typy a rozhraními (což je dynamický odkaz umožňující kachní polymorfismus).

Právě, že to jsou pravé reference, tj. neprůhledné proměnné zprostředkovávající přístup k určitému objektu určitou formou a za určitých podmínek. V tom se blíží definici kapabilit, na rozdíl od pointeru, který je vždycky jenom nativní strojové slovo udávající jedinou adresu v paměti. Kachní polymorfismus je jedním ze scénářů, kde tenhle rozdíl vykrystalizuje, ale jsou i jiné, např. slices (kde reference určuje adresu a velikost). V C++ jsou reference vždycky jenom obyčejné pointery, zatímco např. v Javě pointery nejsou vůbec.

Jester

Re:Velikost pole objektů v Go
« Odpověď #13 kdy: 22. 03. 2018, 03:02:45 »
To už nejsou reference, tady jde o rozdíl mezi konkrétními typy a rozhraními (což je dynamický odkaz umožňující kachní polymorfismus).
Právě, že to jsou pravé reference, tj. neprůhledné proměnné zprostředkovávající přístup k určitému objektu určitou formou a za určitých podmínek. V tom se blíží definici kapabilit, na rozdíl od pointeru, který je vždycky jenom nativní strojové slovo udávající jedinou adresu v paměti. Kachní polymorfismus je jedním ze scénářů, kde tenhle rozdíl vykrystalizuje, ale jsou i jiné, např. slices (kde reference určuje adresu a velikost). V C++ jsou reference vždycky jenom obyčejné pointery, zatímco např. v Javě pointery nejsou vůbec.
Tak tuhle terminologii neznám, ale budiž, vím, o co jde. Každopádně to má Go implementačně dobře vyřešené.

klokan

Re:Velikost pole objektů v Go
« Odpověď #14 kdy: 22. 03. 2018, 05:01:31 »
Tak tuhle terminologii neznám, ale budiž, vím, o co jde. Každopádně to má Go implementačně dobře vyřešené.

Dobře vyřešené to je, ale má to svá plus a mínus. Hlavní výhodou tohoto řešení je, že samotný objekt je čistá struct, proto se s ním dá dobře manipulovat i přes FFI, a navíc volání metod může být u každého objektu buď statické, nebo dynamické (kachní) podle typu reference. Nevýhodou je, že reference můžou být různě velké, jak to ostatně tady překvapilo OP. Například v Rustu bude &Calculon normální pointer, ale &Worker dvojice pointerů a &[Calculon] bude pointer + usize. V C++ je to jednodušší, každá reference je jediný pointer, ale zase musí být vtable (neboli __methods) přímo součástí objektu, takže tento se tím stává složitý a obtížně přístupný "zvenčí".