W jaki sposób wykorzystanie pamięci przez obiekt całkowity napisany w Javie porównuje \ wykorzystanie pamięci przez obiekt całkowity napisany w C ++? Czy różnica jest znikoma? Bez różnicy? Duża różnica? Zgaduję, że jest tak samo, ponieważ int jest int niezależnie od języka (?)
Powodem, dla którego o to zapytałem, jest to, że czytałem o tym, jak ważne jest wiedzieć, kiedy wymagania dotyczące pamięci programu zapobiegną rozwiązaniu danego problemu przez programistę.
Zafascynowała mnie ilość pamięci potrzebnej do stworzenia pojedynczego obiektu Java. Weźmy na przykład obiekt liczb całkowitych. Popraw mnie, jeśli się mylę, ale obiekt całkowity Java wymaga 24 bajtów pamięci:
- 4 bajty dla zmiennej int inst
- 16 bajtów narzutu (odwołanie do klasy obiektu, informacje na temat czyszczenia pamięci i informacje o synchronizacji)
- 4 bajty wypełnienia
Jako kolejny przykład tablica Java (która jest implementowana jako obiekt) wymaga ponad 48 bajtów:
- 24 bajty informacji o nagłówku
- 16 bajtów narzutu obiektu
- 4 bajty długości
- 4 bajty na wypełnienie
- plus pamięć potrzebna do przechowywania wartości
Jak porównują te zastosowania pamięci z tym samym kodem napisanym w C ++?
Kiedyś byłem nieświadomy użycia pamięci przez programy C ++ i Java, które napisałem, ale teraz, gdy zaczynam się uczyć o algorytmach, bardziej doceniam zasoby komputera.
źródło
int
? Jeśli tak, to powinieneś porównać to zint
Javą,Integer
o ile nie masz 32-bitowych int.Odpowiedzi:
To zależy od platformy i implementacji.
C ++ gwarantuje, że rozmiar
char
ma dokładnie jeden bajt i co najmniej 8 bitów szerokości. Zatem rozmiar ashort int
jest co najmniej 16 bitów i nie mniejszy niżchar
. Rozmiarint
jest co najmniej tak duży jak rozmiarshort int
. Rozmiarlong int
to co najmniej 32 bity i nie mniej niż int.sizeof(char) == 1; sizeof(long int) >= sizeof(int) >= sizeof(short int) >= sizeof(bool) >= sizeof(char).
Rzeczywisty model pamięci C ++ jest jednak bardzo zwarty i przewidywalny . Na przykład nie ma metadanych w obiektach, tablicach ani wskaźnikach. Struktury i klasy są ciągłe, tak jak tablice, ale wypełnienie można umieścić w razie potrzeby i potrzeby.
Szczerze mówiąc, takie porównanie jest w najlepszym razie głupie, ponieważ użycie pamięci Java zależy bardziej od implementacji Java niż od uruchamianego kodu.
źródło
int32_t
.Większość odpowiedzi wydaje się ignorować kilka dość istotnych kwestii.
Po pierwsze, w ogromnej ilości Java, praktycznie nigdy nie widzisz surowego
int
- prawie wszystkie zastosowania sąInteger
, więc fakt, żeint
może być (mniej więcej) taki sam jakint
w C lub C ++, jest prawie nieistotny, z wyjątkiem tego ( z mojego doświadczenia wynika, że mały) procent kodu, który używa tylkoint
zamiastInteger
.Po drugie, rozmiary poszczególnych obiektów nie mają prawie nic wspólnego z powierzchnią pamięci programu jako całości. W Javie ślad pamięci programu dotyczy przede wszystkim tego, jak tuning został wyrzucony śmieci. W większości przypadków GC jest dostrojony, aby zmaksymalizować prędkość, co (w dużej mierze) oznacza uruchamianie GC tak rzadko, jak to możliwe.
W tej chwili nie mam przydatnego linku, ale były pewne testy pokazujące, że Java może działać z tą samą prędkością co C, ale aby to zrobić, musisz uruchamiać GC tak rzadko, że używa około 7 razy więcej pamięć. Nie dlatego, że poszczególne obiekty są 7 razy większe, ale dlatego, że GC może stać się dość drogi, jeśli robisz to zbyt często. Co gorsza, GC może zwolnić pamięć tylko wtedy, gdy może „udowodnić”, że nie ma już żadnego sposobu dostępu do obiektu, a nie po prostu, gdy wiesz, że skończyłeś go używać. Oznacza to, że nawet jeśli uruchamiasz GC znacznie częściej, aby zminimalizować zużycie pamięci, prawdopodobnie nadal możesz planować, że typowy program ma większy obszar pamięci. W takim przypadku możesz zmniejszyć współczynnik do 2 lub 3 zamiast 7. Nawet jeśli drastycznie przesadzisz, nie rób tego1 .
W zależności od sytuacji istnieje inny czynnik, który może, ale nie musi być znaczący: pamięć zajmowana przez samą JVM. Jest to mniej więcej ustalone, więc jako wartość procentowa może być ogromna, jeśli aplikacja sama nie potrzebuje dużo pamięci, lub może być niewielka, jeśli aplikacja musi dużo przechowywać. Przynajmniej na mojej maszynie nawet najbardziej trywialna aplikacja Java wydaje się zajmować około 20-25 megabajtów (może być ponad 1000 razy w przypadku programów trywialnych lub prawie niezmiernie mała w przypadku dużych).
1 Nie oznacza to, że nikt nie byłby w stanie napisać Javy z śladem tak zbliżonym do tego, co można uzyskać w C ++. Trzeba tylko powiedzieć, że samo posiadanie tej samej liczby / wielkości obiektów i częste uruchamianie GC z reguły cię tam nie doprowadzi.
źródło
Integer
(dlaczego?)int
. Tylko kolekcje ogólne nie mają innego wyboru, jak użyćInteger
ze względu na wymazanie typu, ale jeśli Ci zależało, możesz je zastąpić implementacją specjalizowaną dlaint
dowolnego pierwotnego typu, którego potrzebujesz. A potem jest tymczasowe boksowanie do przekazywania przez ogólny kod owijania (np. Wszystko, co wymagaObject[]
). Poza tym, czy masz źródła narzutów kosmicznych GC? Tak naprawdę nie wątpię, jestem tylko ciekawy.Mam nadzieję, że zdajesz sobie sprawę, że wszystko to jest ściśle zdefiniowane w implementacji, zarówno dla Java, jak i C ++. To powiedziawszy, model obiektowy Java wymaga sporo miejsca.
Obiekty C ++ (generalnie) nie potrzebują żadnej pamięci poza tym, czego potrzebują członkowie. Zauważ, że (w przeciwieństwie do Javy, gdzie wszystko, co zdefiniowane przez użytkownika jest typem referencyjnym), kod klienta może wykorzystywać obiekty zarówno jako typ wartości, jak i typy referencyjne, tzn. Obiekt może przechowywać wskaźnik / referencję do innego obiektu lub przechowywać obiekt bezpośrednio bez pośrednictwa. Jeden dodatkowy wskaźnik na obiekt jest konieczny, jeśli istnieją jakieś
virtual
metody, ale całkiem sporo użytecznych klas zaprojektowano tak, aby radziły sobie bez polimorfizmu i nie potrzebują tego. Brak metadanych GC i blokady dla poszczególnych obiektów. Zatemclass IntWrapper { int x; public: IntWrapper(int); ... };
obiekty nie potrzebują więcej miejsca niż zwykłeint
s i mogą być umieszczane bezpośrednio (tj. Bez pośrednictwa) w kolekcjach i innych obiektach.Tablice są trudne, ponieważ nie ma gotowego, wspólnego odpowiednika tablicy Java w C ++. Możesz po prostu przydzielić wiązkę obiektów
new[]
(bez absolutnie żadnych narzutów / metadanych), ale nie ma pola długości - implementacja prawdopodobnie przechowuje jeden, ale nie masz do niego dostępu.std::vector
jest tablicą dynamiczną, a zatem ma dodatkowe obciążenie i większy interfejs.std::array
i tablice w stylu C (int arr[N];
), potrzebujesz stałej czasowej kompilacji. Teoretycznie powinna to być tylko pamięć obiektu plus jedna liczba całkowita na długość - ale ponieważ możesz uzyskać dynamiczne zmiany rozmiaru i w pełni funkcjonalny interfejs z bardzo małą dodatkową przestrzenią, po prostu idziesz do tego w praktyce. Zauważ, że wszystkie te, a także wszystkie inne kolekcje, domyślnie przechowują obiekty według wartości, oszczędzając w ten sposób pośredniość i miejsce na referencje oraz poprawiając zachowanie pamięci podręcznej. Musisz jawnie przechowywać wskaźniki (inteligentne, proszę), aby uzyskać pośrednie.Powyższe porównania nie są do końca uczciwe, ponieważ niektóre z tych oszczędności wynikają z nieuwzględnienia funkcji zawartych w Javie, a ich odpowiednik C ++ jest często mniej zoptymalizowany niż odpowiednik Java (*). Powszechny sposób implementacji
virtual
w C ++ nakłada dokładnie tyle samo kosztów ogólnych, co powszechny sposób implementacjivirtual
w Javie. Aby uzyskać blokadę, potrzebujesz w pełni funkcjonalnego obiektu mutex, który najprawdopodobniej jest większy niż kilka bitów. Aby uzyskać liczenie referencji ( nieodpowiednik GC i nie powinien być używany jako taki, ale czasem przydatny), potrzebujesz inteligentnego wskaźnika, który dodaje pole zliczania referencji. O ile obiekt nie jest skonstruowany ostrożnie, licznik referencji, obiekt inteligentnego wskaźnika i obiekt odniesienia znajdują się w całkowicie oddzielnych lokalizacjach, a nawet jeśli zbudujesz go poprawnie, wspólny wskaźnik może (musi?) Nadal mieć dwa wskaźniki zamiast jednego. Z drugiej strony, dobry styl C ++ nie wykorzystuje tych funkcji na tyle, aby miało to znaczenie - w praktyce dobrze napisane obiekty biblioteki C ++ zużywają mniej. To niekoniecznie oznacza mniejsze zużycie pamięci, ale oznacza, że C ++ ma dobry start w tym zakresie.(*) Na przykład można uzyskać wirtualne połączenia, kody skrótu tożsamości i blokowanie za pomocą tylko jednego słowa dla niektórych obiektów (i dwóch słów dla wielu innych obiektów) poprzez połączenie informacji o typie z różnymi flagami i usunięcie bitów blokady dla obiektów, które są prawdopodobnie nie będzie potrzebował zamków. Zobacz efektywne pod względem miejsca i czasu wdrożenie Java Object Model (PDF) autorstwa Davida F. Bacona, Stephena J. Finka i Davida Grove'a, aby uzyskać szczegółowe wyjaśnienie tej i innych optymalizacji.
źródło
Zwykły
int
, w java, zajmuje dokładnie tyle samo miejsca, coint
w C ++, pod warunkiem, że obie implementacje używają tego samego rozmiaru liczby całkowitej i wyrównania pamięci.Int „obiekt” ( liczba całkowita w ramce , czyli instancja klasy
Integer
), przenosi cały narzut instancji klasy w Javie, więc jest znacznie większy niżint
w C ++. Jeśli jednak chcesz wyposażyć obiekt w C ++ w te same funkcje, które są dostarczane z obiektami Java od razu po wyjęciu z pudełka (polimorfizm, boks, wyrzucanie elementów bezużytecznych, RTTI), prawdopodobnie uzyskasz obiekt równy rozmiar.A potem są kwestie optymalizacji; ponieważ modele wykonania i paradygmaty programowania różnią się, jest mało prawdopodobne, aby każdy nietrywialny problem został rozwiązany tak samo w obu językach, więc porównywanie wielkości pamięci na tym poziomie nie ma większego sensu.
Tak, obiekty Java domyślnie niosą narzut więcej niż klasy C ++, ale mają więcej funkcji, co prowadzi do innego stylu programowania - dobry programista może wykorzystać zalety obu stron.
źródło