Dlaczego wielkość prymitywu logicznego Javy nie została zdefiniowana?

111

Specyfikacja wirtualnej maszyny języka Java mówi, że wsparcie dla wartości logicznych jest ograniczone typów pierwotnych .

Nie ma instrukcji maszyny wirtualnej Javy poświęconej wyłącznie operacjom na wartościach logicznych. Zamiast tego wyrażenia w języku programowania Java, które operują na wartościach logicznych, są kompilowane w celu użycia wartości typu danych int maszyny wirtualnej Java.

Z powyższego wynika (chociaż mogłem to źle zinterpretować), że typ danych int jest używany podczas operacji na logicznych, ale jest to konstrukcja pamięci 32-bitowej. Biorąc pod uwagę, że wartość logiczna reprezentuje tylko 1 bit informacji:

  • Dlaczego typ bajtowy lub krótki nie jest używany jako proxy dla wartości logicznej zamiast int?
  • Jaki jest najbardziej niezawodny sposób sprawdzenia, ile pamięci jest używane do przechowywania typu boolowskiego dla dowolnej maszyny JVM?
Joel
źródło

Odpowiedzi:

116

Krótka odpowiedź: tak, wartości logiczne są manipulowane jako jednostki 32-bitowe, ale tablice wartości logicznych zajmują 1 bajt na element.

Dłuższa odpowiedź: maszyna JVM używa 32-bitowej komórki stosu używanej do przechowywania zmiennych lokalnych, argumentów metod i wartości wyrażeń. Prymitywy mniejsze niż 1 komórka są wypełniane, prymitywy większe niż 32 bity (długie i podwójne) zajmują 2 komórki. Ta technika minimalizuje liczbę rozkazów, ale ma pewne szczególne skutki uboczne (takie jak potrzeba maskowania bajtów).

Prymitywy przechowywane w tablicach mogą używać mniej niż 32 bity, a istnieją różne opkody do ładowania i przechowywania wartości pierwotnych z tablicy. Wartości logiczne i bajtowe używają zarówno kodów, jak baloadi bastoreopkodów, co oznacza, że ​​tablice logiczne zajmują 1 bajt na element.

Jeśli chodzi o układ obiektów w pamięci, jest to objęte regułami „prywatnej implementacji” , może to być 1 bit, 1 bajt lub, jak zauważył inny plakat, wyrównane do 64-bitowej granicy podwójnych słów. Najprawdopodobniej przyjmuje podstawowy rozmiar słowa podstawowego sprzętu (32 lub 64 bity).


Jeśli chodzi o minimalizację ilości miejsca używanego przez wartości logiczne: to naprawdę nie stanowi problemu dla większości aplikacji. Ramki stosu (przechowujące zmienne lokalne i argumenty metod) nie są zbyt duże, aw dużym schemacie dyskretna wartość logiczna w obiekcie również nie jest taka duża. Jeśli masz wiele obiektów z wieloma wartościami logicznymi, możesz użyć pól bitowych, które są zarządzane przez twoje metody pobierające i ustawiające. Jednak zapłacisz karę za czas procesora, która jest prawdopodobnie większa niż kara w pamięci.

kdgregory
źródło
W przypadku członków klasy logicznej / bajtowej, czy prawdą jest również, że mają one również 4 bajty? Instancja klasy jest alokowana jako całość na stosie, więc mogę sobie wyobrazić, że JVM powinna prawdopodobnie używać 1 bajtu na element logiczny / bajtowy, a na koniec wykonać 4-bajtowe wyrównanie dla całej instancji klasy. Czy tak jest? (jeśli masz referencje, które to potwierdzają, udostępnij je)
dma_k
@dma_k: jak zauważyłem w mojej odpowiedzi, układ instancji klasy jest zależny od implementacji. Zwróć jednak uwagę, że instancje klas nie są przechowywane w stosie, ale na stercie (chociaż zobaczysz pewne odniesienia do „analizy ucieczki” JDK 7 przenoszącej obiekty ze stosu na stos, wydaje się, że tak nie jest; zobacz java.sun.com/javase/7/docs/technotes/guides/vm/…)
kdgregory
1
Czasami pakowanie wartości logicznych może być w rzeczywistości szybsze. Ilekroć rozmiar pamięci podręcznej ma znaczenie, lepiej spakować rzeczy. Na przykład segmentowe sito główne działa w kawałkach 32 kB (rozmiar pamięci podręcznej L1) jest znacznie szybsze niż sito niesegmentowane. Między kawałkami jest trochę narzutu, a przy pakowaniu płacisz osiem razy rzadziej. Jeszcze tego nie zmierzyłem.
maaartinus
7

Pojedyncza wartość logiczna gdzieś w hierarchii dziedziczenia może używać do 8 bajtów! Wynika to z wypełnienia. Więcej szczegółów można znaleźć w artykule Ile pamięci jest używane przez mój obiekt Java? :

Wracając do pytania, ile zużywa wartość logiczna, tak, zużywa co najmniej jeden bajt, ale ze względu na reguły wyrównania może zużywać znacznie więcej. IMHO bardziej interesujące jest wiedzieć, że boolean [] zużyje jeden bajt na wpis, a nie jeden bit, plus trochę narzutu z powodu wyrównania i dla pola rozmiaru tablicy. Istnieją algorytmy grafowe, w których duże pola bitów są przydatne i musisz być świadomy, że jeśli używasz boolean [], potrzebujesz prawie dokładnie 8 razy więcej pamięci niż jest to naprawdę potrzebne (1 bajt kontra 1 bit).

akuhn
źródło
Jak zresztą użyłbyś logicznej []?
Thomas Jung,
boolean [] może być użyty jako maska. Czasami jednak BitSet może być lepszy, ponieważ ma kilka przydatnych metod.
Michael Munsey
5

Piąte wydanie Java in a Nutshell (O'Reilly) mówi, że prymitywny typ logiczny ma 1 bajt. To może być błędne, biorąc pod uwagę to, co pokazuje badanie sterty. Zastanawiam się, czy większość maszyn JVM ma problemy z przydzielaniem mniej niż bajtu dla zmiennych.

Matthew Flynn
źródło
3

Mapowanie boolowskie zostało wykonane z myślą o 32-bitowym procesorze. Wartość int ma 32 bity, więc można ją przetworzyć w jednej operacji.

Oto rozwiązanie z Java IAQ Petera Norviga: Rzadkie odpowiedzi na pytania dotyczące pomiaru rozmiaru (z pewną niedokładnością):

static Runtime runtime = Runtime.getRuntime();
...
long start, end;
Object obj;
runtime.gc();
start = runtime.freememory();
obj = new Object(); // Or whatever you want to look at
end =  runtime.freememory();
System.out.println("That took " + (start-end) + " bytes.");
Thomas Jung
źródło
Ponieważ ta rozmowa dotyczy prymitywów, musisz wykazać się kreatywnością w testowaniu tego, ponieważ prymitywy nie są przechowywane w stercie, chyba że są polami w instancji lub tablicy. Żaden z nich nie odpowiada na pytanie, w jaki sposób Java zdecyduje się przechowywać go w stosie.
Jesse,
2

Procesory działają na określonej długości typu danych. W przypadku procesorów 32-bitowych mają one długość 32 bitów i dlatego w Javie nazywamy to „int”. Wszystko poniżej lub powyżej, które musi zostać wypełnione lub podzielone do tej długości, zanim procesor będzie mógł to przetworzyć. Nie zajmuje to dużo czasu, ale jeśli potrzebujesz 2 cykli procesora zamiast 1 do podstawowych operacji, oznacza to podwojenie kosztów / czasu.

Ta specyfikacja jest przeznaczona dla 32-bitowych procesorów, aby mogły przetwarzać wartości logiczne z ich rodzimym typem danych.

Możesz mieć tylko jedną: prędkość lub pamięć - SUN zdecydował się na prędkość.

Mocno zakodowane
źródło
1

Boolean reprezentuje jeden fragment informacji, ale jego „rozmiar” nie jest czymś, co jest precyzyjnie zdefiniowane, mówią tutoriale Sun Java. Literały logiczne mają tylko dwie możliwe wartości: prawda i fałsz. Aby uzyskać szczegółowe informacje, zobacz Typy danych Java .

Krishan
źródło
-10

Dlaczego nie utworzyć takiego pliku .java:

Empty.java

class Empty{
}

i jedną taką klasę:

NotEmpty.java

class NotEmpty{
   boolean b;
}

Skompiluj je oba i porównaj pliki .class z edytorem szesnastkowym.

mring
źródło
5
jest to zupełnie inna miara, niezwiązana z wielkością prymitywnego typu boolowskiego w pamięci.
Joel