Article View: pl.comp.lang.delphi
Article #346839Re: Nowe Delphi
From: Krzysztof Szyszka
Date: Sat, 03 Nov 2018 12:23
Date: Sat, 03 Nov 2018 12:23
119 lines
7049 bytes
7049 bytes
> >> function Test(wartosc : integer) : Integer; > >> var > >> WielkaTablica : array[milion] of Integer; > >> begin > >> if wartosc > 10 then > >> begin > >> result := WielkaTablica[wartosc]; > >> end; > >> end; > > > > Piszesz o typach zarządzalnych, a podajesz, jako przykład deklarację lokalnej tablicy > > o stałym rozmiarze alokowaną na stosie. Nikt, o zdrowych zmysłach, nie zadeklaruje > > tablicy o takim rozmiarze na stosie, a jakby się taki znalazł, to dostanie na wejściu do > > tej funkcji "stack overflow". > > Masz rację co do niepraktyczności przykładu, po prostu chodziło mi o jasny > przekaz i na kolanie to napisałem, ale przyjąłem niepoprawny typ tej > tablicy, gdyby był of string to byłoby to o co chodzi. Lub rekord czy > tablica rekordów. Wystarczyło zadeklarować tablicę dynamiczną jako WielkaTablica: array of Integer, ale wtedy nie mógłbyś pisać o niepotrzebnej alokacji 4 MB RAMu, bo taka deklaracja powoduje jedynie powiększenie ramki stosu przy wejściu do tej funkcji o 4 bajty! Te dodatkowe 4 bajty na stosie zajmuje referencja do WielkiejTablicy, której jeszcze nie ma i zostanie utworzona (lub nie) dopiero w kodzie funkcji przy użyciu SetLength. Ale przy wejściu do funkcji ta referencja musi być ustawiona na Nil, żeby przy wyjściu z funkcji nie zawierała śmieci, jeśli nie dojdzie do alokacji tablicy przez SetLength. > >> Wywołanie powyższej metody powoduje, że na początku tablica jest alokowana > >> (4 MIB ramu!), a na końcu zwalniana, nawet jeśli jej nie tkniemy! Tak teraz > >> to działa, można zobaczyć w oknie ASM debugera. > >> > >> Teraz, po nowemu gdy będzie tak: > > > >> function Test(wartosc : integer) : Integer; > >> begin > >> if wartosc > 10 then > >> begin > >> var WielkaTablica : array[milion] of Integer; > >> result := WielkaTablica[wartosc]; > >> end; > >> end; > > > >> To tylko jeśli wartosc wejściowa spełni warunek i wykonanie wejdzie w > >> begin/end warunku to nastąpi alokacja i zwolnienie, w innych przypadkach > >> nie tknie pamięci! > > > > W tym przypadku nic się nie zmieni, jeśli chodzi o miejsce i moment alokacji > > pamięci dla tej konkretnej tablicy - nadal będzie rezerwowana na stosie > > w momencie wejścia do funkcji Test. Ale żeby była jasność - ta tablica nie jest > > zmienną zarządzalną. Podając przykład z tą tablicą tylko namieszałeś ludziom > > w głowach. > > Zmieni się ten aspekt właśnie, alokacja będzie w chwili użycia a nie po > wejściu do procki. I to jest olbrzymia różnica, która mnie cieszy. No właśnie nie rozróżniasz dwóch pojęć: czym innym jest alokacja (przydział pamięci), a czym innym inicjalizacja (ustawienie wartości początkowej dla referencji). W tym drugim przypadku nic się nie zmieni w kwestii alokacji pamięci. Nadal przy wejściu do funkcji zostaną zarezerwowane 4 bajty na referencję do WielkaTablica, ale nie zostaną zainicjalizowane wartością Nil. Inicjalizacja (i finalizacja) tej referencji nastąpi dopiero wtedy, gdy program wejdzie do bloku warunkowego. Jeśli nie wejdzie, to referencja nie będzie ani inicjalizowana, ani finalizowana i dlatego mówi się, że ta zmienna poza tym blokiem nie istnieje (choć ma przydzielone 4 bajty na stosie). > >> I teraz przełóżmy to na 10 zmiennych lokalnych, to nawet mogą być puste > >> stringi, nastąpi ich alokacja i zwolnienie. I teraz tak w każdej > >> metodzie... czujesz olbrzymią wydajnościową różnicę? Ja tak. > > > > Wydajnościowo, to czasem może być nawet gorsze od deklarowania wszystkich > > zmiennych na początku procedury/funkcji, jeśli ktoś nie wie, gdzie i kiedy są > > alokowane zmienne zadeklarowane w lokalnych blokach begin end i jak często > > są inicjalizowane i finalizowane (np. w pętli). > > Niewiedza zawsze będzie przyczyną problemów, ale nie o tym mowa, nie na tym > się skupiajmy. Ale właśnie niewiedza jest przyczyną Twojej błędnej interpretacji wprowadzonych Inlined Varaibles i Twojego huraoptymizmu ;-) > > Jeśli w takim bloku begin end zadeklarujemy choć jedną zmienną zarządzalną, > > to automatycznie zostanie utworzona kolejna ramka stosu, a to kosztuje > > tyle samo, co utworzenie kolejnego bloku try finally end, tylko niejawnego. > > > Natomiast zysk wydajnościowy z używania "inlined variables" (nie wiem, > > jak to przetłumaczyć na polski) jest niewielki i dotyczy jedynie prostych > > operacji, których czasem może nie być, czyli ustawienia wskaźnika na nil > > podczas inicjalizacji zmiennej zarządzalnej oraz sprawdzenia, czy wskaźnik > > nie jest nil, przy jej finalizacji. > > Moje odczucia okazuje się nie są całkiem samotne: > > https://blog.grijjy.com/2018/11/02/inline-variables-can-increase-performance/ A ten przykład podany przez Erika bardzo dobrze pokazuje różnice pomiędzy TestLocalVars i TestInlinedVars. Tylko, że Erik nie wprowadza ludzi w błąd i nie pisze o zmianach w alokacji zmiennych, tak jak Ty to rozumiesz, ale jasno wskazuje na różnice dotyczące miejsca inicjalizacji i finalizacji zmiennych. "Now, the initialization and finalization code is only executed if necessary. This improves performance, especially of ACondition is usually False." A na koniec Eric przestrzega przed tym samym, na co ja zwróciłem uwagę, a Ty skwitowałeś to tekstem "nie o tym mowa, nie na tym się skupiajmy". "Currently, inline variables can increase the size of the generated code, especially if they are of a managed type. This extra code also makes inline managed variables not as efficient as they could be. But then again, this is version 1.0 of this feature, so we could see improvements in the future." -- pozdrowienia Krzysztof Szyszka, X-Files Software Developer of X-DBGrid Component Embarcadero Technology Partner http://www.x-files.pl/
Technical Details
Message-ID:
<prk3vn$usl$1@node1.news.atman.pl>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed2.atman.pl!newsfeed.atman.pl!.POSTED!not-for-mailReferences:
<7376c5jxe41w$.dlg@tyczka.com> <d60ae831-92ca-4e7f-8a06-29012c3ac596@googlegroups.com> <5bcrkgobe6zx$.dlg@tyczka.com> <prabqd$l4g$1@node1.news.atman.pl> <3bw41qiju5jm.dlg@tyczka.com>Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed2.atman.pl!newsfeed.atman.pl!.POSTED!not-for-mail From: "Krzysztof Szyszka" <nomail@gazeta.pl> Newsgroups: pl.comp.lang.delphi Subject: Re: Nowe Delphi Date: Sat, 3 Nov 2018 13:23:04 +0100 Organization: ATMAN - ATM S.A. Lines: 120 Message-ID: <prk3vn$usl$1@node1.news.atman.pl> References: <7376c5jxe41w$.dlg@tyczka.com> <d60ae831-92ca-4e7f-8a06-29012c3ac596@googlegroups.com> <5bcrkgobe6zx$.dlg@tyczka.com> <prabqd$l4g$1@node1.news.atman.pl> <3bw41qiju5jm.dlg@tyczka.com> NNTP-Posting-Host: 89-77-104-79.dynamic.chello.pl Mime-Version: 1.0 X-Trace: node1.news.atman.pl 1541247799 31637 89.77.104.79 (3 Nov 2018 12:23:19 GMT) X-Complaints-To: usenet@atman.pl NNTP-Posting-Date: Sat, 3 Nov 2018 12:23:19 +0000 (UTC) In-Reply-To: <3bw41qiju5jm.dlg@tyczka.com> X-Priority: 3 X-MSMail-Priority: Normal Importance: Normal X-Newsreader: Microsoft Windows Live Mail 16.4.3528.331 X-MimeOLE: Produced By Microsoft MimeOLE V16.4.3528.331 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit