Mengapa ukuran primitif boolean Java tidak ditentukan?

111

The Java Virtual Machine Spesifikasi mengatakan bahwa ada dukungan terbatas untuk boolean primitif jenis.

Tidak ada instruksi mesin virtual Java yang hanya didedikasikan untuk operasi pada nilai boolean. Sebaliknya, ekspresi dalam bahasa pemrograman Java yang beroperasi pada nilai boolean dikompilasi untuk menggunakan nilai tipe data int mesin virtual Java.

Hal di atas menyiratkan (walaupun saya mungkin telah salah menafsirkannya) bahwa tipe data int digunakan ketika beroperasi pada boolean, tetapi ini adalah konstruksi memori 32 bit. Mengingat bahwa boolean hanya mewakili 1 bit informasi:

  • Mengapa byte, atau short, type tidak digunakan sebagai proxy untuk boolean, bukan int?
  • Untuk JVM tertentu, apa cara paling andal untuk mengetahui dengan tepat berapa banyak memori yang digunakan untuk menyimpan jenis boolean?
Joel
sumber

Jawaban:

116

Jawaban singkatnya: ya, nilai boolean dimanipulasi sebagai entitas 32-bit, tetapi array boolean menggunakan 1 byte per elemen.

Jawaban yang lebih panjang: JVM menggunakan stack cell 32-bit, yang digunakan untuk menampung variabel lokal, argumen metode, dan nilai ekspresi. Primitif yang lebih kecil dari 1 sel dilapisi, primitif yang lebih besar dari 32 bit (panjang dan ganda) mengambil 2 sel. Teknik ini meminimalkan jumlah opcode, tetapi memiliki beberapa efek samping yang aneh (seperti kebutuhan untuk menutupi byte).

Primitif yang disimpan dalam array dapat menggunakan kurang dari 32 bit, dan ada opcode berbeda untuk memuat dan menyimpan nilai primitif dari array. Nilai Boolean dan byte sama-sama menggunakan opcode baloaddan bastore, yang menyiratkan bahwa array boolean mengambil 1 byte per elemen.

Sejauh tata letak objek dalam memori berjalan, ini tercakup di bawah aturan "implementasi pribadi" , itu bisa 1 bit, 1 byte, atau seperti yang dicatat poster lain, disejajarkan dengan batas kata ganda 64-bit. Kemungkinan besar, ini mengambil ukuran kata dasar dari perangkat keras yang mendasarinya (32 atau 64 bit).


Sejauh meminimalkan jumlah ruang yang digunakan boolean: sebenarnya tidak menjadi masalah bagi sebagian besar aplikasi. Stack frame (menampung variabel lokal dan argumen metode) tidak terlalu besar, dan dalam skema besar, boolean diskrit dalam sebuah objek juga tidak terlalu besar. Jika Anda memiliki banyak objek dengan banyak boolean, Anda dapat menggunakan bit-field yang dikelola melalui getter dan setter. Namun, Anda akan membayar penalti dalam waktu CPU yang mungkin lebih besar dari hukuman dalam memori.

kdgregory
sumber
Untuk anggota kelas boolean / byte, apakah benar juga, bahwa mereka juga 4 byte? Instance kelas dialokasikan secara keseluruhan di stack, jadi saya dapat membayangkan, JVM mungkin harus menggunakan 1 byte per anggota boolean / byte dan akhirnya membuat penyelarasan 4-byte untuk instance kelas lengkap. Begitu? (jika Anda memiliki referensi yang membuktikan hal ini, silakan, bagikan)
dma_k
@dma_k: seperti dicatat dalam tanggapan saya, tata letak instance kelas bergantung pada implementasi. Namun, perhatikan bahwa instance kelas tidak disimpan di tumpukan, mereka disimpan di heap (meskipun Anda akan melihat beberapa referensi ke objek "escape analysis" JDK 7 yang memindahkan dari tumpukan ke heap, tampaknya tidak demikian; lihat java.sun.com/javase/7/docs/technotes/guides/vm/…)
kdgregory
1
Terkadang mengemas boolean sebenarnya lebih cepat. Kapan pun ukuran cache penting, mungkin lebih baik untuk mengemasnya. Misalnya, saringan utama tersegmentasi bekerja dalam potongan 32 kB (ukuran cache L1) jauh lebih cepat daripada saringan non-segmen. Ada beberapa biaya tambahan di antara potongan-potongan dan dengan pengepakan Anda membayar biaya overhead delapan kali lebih jarang. Saya belum mengukurnya.
maaartinus
7

Satu boolean di suatu tempat dalam hierarki pewarisan dapat menggunakan hingga 8 byte! Ini karena bantalan. Detail selengkapnya dapat ditemukan di Berapa banyak memori yang digunakan oleh objek Java saya? :

Kembali ke pertanyaan tentang berapa banyak yang dikonsumsi boolean, ya itu mengkonsumsi setidaknya satu byte, tetapi karena aturan penyelarasan, itu mungkin memakan lebih banyak. IMHO lebih menarik untuk mengetahui bahwa boolean [] akan mengkonsumsi satu byte per entri dan bukan satu bit, ditambah beberapa overhead karena penyelarasan dan untuk bidang ukuran array. Ada algoritme grafik di mana bidang besar bit berguna, dan Anda perlu menyadari bahwa, jika Anda menggunakan boolean [], Anda membutuhkan memori hampir 8 kali lebih banyak daripada yang sebenarnya dibutuhkan (1 byte versus 1 bit).

akuhn
sumber
Bagaimana cara menggunakan boolean []?
Thomas Jung
boolean [] bisa digunakan untuk topeng. Terkadang BitSet bisa lebih baik, karena memiliki beberapa metode yang berguna.
Michael Munsey
5

Edisi ke-5 Java in a Nutshell (O'Reilly) mengatakan tipe primitif boolean adalah 1 byte. Itu bisa salah, berdasarkan apa yang ditunjukkan oleh pemeriksaan heap. Saya ingin tahu apakah sebagian besar JVM memiliki masalah dengan mengalokasikan kurang dari satu byte untuk variabel.

Matthew Flynn
sumber
3

Pemetaan boolean dilakukan dengan CPU 32-bit. Nilai int memiliki 32 bit sehingga dapat diproses dalam satu kali operasi.

Berikut adalah solusi dari IAQ Java Peter Norvig: Pertanyaan yang Sering Dijawab untuk mengukur ukuran (dengan beberapa ketidaktepatan):

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
sumber
Karena percakapan ini tentang primitif, Anda harus kreatif dalam menguji ini karena primitif tidak disimpan di heap kecuali mereka adalah bidang pada sebuah instance atau larik. Dan tak satu pun dari mereka menjawab pertanyaan tentang bagaimana Java akan memilih untuk menyimpannya di stack.
Jesse
2

CPU beroperasi pada panjang tipe data tertentu. Untuk CPU 32bit, panjangnya 32 bit dan oleh karena itu disebut 'int' di Java. Segala sesuatu di bawah atau di atasnya yang harus diisi atau dipisahkan dengan panjang ini sebelum CPU dapat memprosesnya. Ini tidak memakan banyak waktu, tetapi jika Anda membutuhkan 2 siklus CPU, bukan 1 untuk operasi dasar, ini berarti biaya / waktu dua kali lipat.

Spesifikasi ini didedikasikan untuk CPU 32bit sehingga mereka dapat memproses boolean dengan tipe data asli mereka.

Anda hanya dapat memiliki satu di sini: kecepatan atau memori - SUN memutuskan kecepatan.

Hardcode
sumber
1

Boolean mewakili satu bit informasi, tetapi "ukurannya" bukanlah sesuatu yang didefinisikan secara tepat, katakanlah tutorial Sun Java. Literal Boolean hanya memiliki dua kemungkinan nilai, yaitu benar dan salah. Lihat Tipe Data Java untuk detailnya.

Krishan
sumber
-10

Mengapa tidak membuat satu file .java seperti ini:

Empty.java

class Empty{
}

dan satu kelas seperti ini:

NotEmpty.java

class NotEmpty{
   boolean b;
}

Kompilasi keduanya dan bandingkan file .class dengan hex editor.

mring
sumber
5
ini adalah metrik lain yang sama sekali, tidak terkait dengan ukuran tipe boolean primitif dalam memori.
Yoel