Optymalizacja - czy warto?

0

Witam
Pisze mały programik do wyłączania komputera po określonym czasie i nie chcąc korzystać z DateTime napisałem odliczanie czasu po swojemu. Mam jednak jeden problem, mianowicie nie mam pomysłu jak się pozbyć nadmiarowego tworzenia stringów. Z tego co zauważyłem GC uruchamia się co około 1.5 sec, za każdym razem uwalnia 0.2 MB pamięci.

 
class Time
    {
        private byte days;
        private ushort hours;
        private uint minutes;
        private byte seconds;

        public Time()
        {
            days = 0;
            hours = 0;
            minutes = 0;
            seconds = 0;
        }

        public void AddMinutes(uint min)
        {
            minutes += min;
            ConvertTime();
        }

        private void ConvertTime()
        {
            while (minutes > 59)
            {
                minutes -= 60;
                hours += 1;
            }
            while (hours > 23)
            {
                hours -= 24;
                days += 1;
            }
            if (days > 99)
            {
                days = 99;
                hours = 23;
                minutes = 59;
                seconds = 59;
            }
        }

        public void SubSecond()
        {
            if (seconds > 0)
            {
                seconds -= 1;
            }
            else
            {
                CarryMinute();
            }
        }

        private void CarryMinute()
        {
            if (minutes > 0)
            {
                minutes -= 1;
                seconds = 58;
            }
            else
            {
                CarryHour();
            }

        }

        private void CarryHour()
        {
            if (hours > 0)
            {
                hours -= 1;
                minutes = 59;
                seconds = 58;
            }
            else
            {
                CarryDay();
            }
        }

        private void CarryDay()
        {
            if (days > 0)
            {
                days -= 1;
                hours = 23;
                minutes = 59;
                seconds = 58;
            }
        }

        public override string ToString()
        {
            string sDays = ChangeToString(days),
                   sHours = ChangeToString(hours),
                   sMinutes = ChangeToString(minutes),
                   sSeconds = ChangeToString(seconds);
            return string.Format("{1}{0}{2}{0}{3}{0}{4}", ":", sDays, sHours, sMinutes, sSeconds);
        }

        private string ChangeToString(uint number)
        {
            if (number < 10)
            {
                return string.Format("{0}{1}", "0", number);
            }
            else
            {
                return string.Format("{0}", number);
            }
        }
    }
1

Nie wiem, co chcesz osiągnąć, ani jak miałoby to zastąpić DateTime, ale taki konstruktor nic nie robi, więc jest tu zupełnie niepotrzebny, zaś zamiast swojej metody ChangeToString mógłbyś po prostu użyć string.Format("{0:D2}", mójInt); albo mójInt.ToString("D2").

0

Konkretnie to chciałem uniknąć ciągłego tworzenia obiektu DateTime, bo działa on tak samo jak string mianowicie każda zmiana wiąże się z utworzeniem nowej instancji.

time = time.AddSeconds(-1);

Teraz własnie chciałem zminimalizować ilość tworzonych stringów, tak jak radziłeś już pozbyłem się funkcji ChangeToString().

0

To ile tych obiektów DateTime tworzysz, że spowalnia Ci to całą aplikację?

0

Tworze nowy co 1 sekundę i nie odczuwam zwolnienie w zadnym stopniu, ale zauważam duży wzrost zużycia pamięci z 2,4MB do 3,4 MB, nie używając DateTime już zaoszczędziłem 0.5 MB, te pozostałe 0.5 MB zabierają stringi i własnie ich chciałem się w jakiś sposób pozbyć.

1

I co masz za problem z tym GC? Są projekty gdzie co sekundę zdejmuje się 300MB albo i więcej (serwery Minecrafta i genialne notchowe programowanie ftw!). To całe 0.2MB pamięci to jak kropla w morzu, szczególnie że co 1.5 sekundy, o ile wierzyć Twoim pomiarom.

Stringi w C#, podobnie jak w Javie są niemutowalne (immutable). Ta ich właściwość wynika z użytego wzorca projektowego i koncepcji - próba ucieczki od tego jest bez sensu i tylko poryje Twój kod zamiast zdziałać cokolwiek sensownego. Wywal tę klasę i zrób normalnie, obecnie marnujesz czas na robienie mikrooptymalizacji. Życiowy przykład: to jak uchwalać konstytucję i zmieniać 30 ustaw tylko po to, żeby zmniejszyć wynagrodzenie posła o 3zł, w czasie kiedy dziura budżetowa wynosi 300 mld złotych.

zauważam duży wzrost zużycia pamięci z 2,4MB do 3,3 MB

A co? Piszesz oprogramowanie do ekspresu do kawy i musisz zmieścić się w 2KB RAMu? Nie? To olej to i nie zawracaj sobie głowy, statystyczny user ma 1-2GB RAMu.

0
Bumcykowy napisał(a):

te pozostałe 0.5 MB zabierają stringi i własnie ich chciałem się w jakiś sposób pozbyć.

Jak Ty to zmierzyłeś?

0

Dałem sobie już z tym spokój. A co do mierzenia to w task manager obserwowałem zużycie pamięci po włączeniu odliczania, dało się zauważyć że rosło do pewnej granicy, w moim programie podczas odliczania są alokowane tylko stringi.

2

Konkretnie to chciałem uniknąć ciągłego tworzenia obiektu DateTime, bo działa on tak samo jak string mianowicie każda zmiana wiąże się z utworzeniem nowej instancji.

Oj, coś kręcisz. Jak i gdzie tworzysz te DateTime?
To jest structura, wg dokumentacji zawierająca 64-bitową liczbę.
w C# (właściwie: w .NET Framework) struktury będące zmiennymi lokalnymi są przechowywane na stosie, więc przestają istnieć w momencie gdy wychodzą z zasięgu, bez czekania na garbage collector.

Możesz sobie miliard razy w pętli for robić new DateTime(), a ilość użytej pamięci nie będzie wcale rosnąć.

Jeśli struktura jest polem pewnej klasy, wtedy co prawda leży na stercie (tam gdzie klasa), ale i tak ciągłe jej nadpisywanie nie powoduje alokacji nowej pamięci, tylko zapis w tym samym miejscu.

Musiałbyś chyba ciągle dodawać DateTime jako elementy listy, żeby rosło zużycie pamięci.

Bardziej prawdopodobne jest, że użycie DateTime powoduje załadowanie dodatkowej biblioteki Frameworka, stąd może być wzrost zużycia pamięci o kilkaset kilobajtów.

stringi to co innego - te faktycznie podlegają normalnemu odśmiecaniu.

Tylko że jeśli przejmujesz się 3 megabajtami pamięci, to .NET nie jest dla ciebie. Typowy program pożera kilkadziesiąt mega już na start...

To nie jest narzędzie odpowiednie, gdy zależy nam na minimalnym zużyciu pamięci.

1

Od samego początku bylem w błędzie, nie sprawdziłem sobie ze DateTime to jednak struktura.

1 użytkowników online, w tym zalogowanych: 0, gości: 1