Tại sao kích thước nguyên thủy boolean của Java không được xác định?


111

Các Java Virtual Machine Đặc điểm kỹ thuật nói rằng có hỗ trợ giới hạn cho boolean nguyên thủy loại.

Không có hướng dẫn máy ảo Java nào chỉ dành riêng cho các thao tác trên các giá trị boolean. Thay vào đó, các biểu thức trong ngôn ngữ lập trình Java hoạt động trên các giá trị boolean được biên dịch để sử dụng các giá trị của kiểu dữ liệu int máy ảo Java.

Ở trên ngụ ý (mặc dù tôi có thể đã hiểu sai) rằng kiểu dữ liệu int được sử dụng khi hoạt động trên boolean, nhưng đây là một cấu trúc bộ nhớ 32 bit. Cho rằng boolean chỉ đại diện cho 1 bit thông tin:

  • Tại sao kiểu byte hoặc ngắn gọn không được dùng làm proxy cho boolean thay vì int?
  • Đối với bất kỳ JVM nào, cách đáng tin cậy nhất để tìm ra chính xác lượng bộ nhớ được sử dụng để lưu trữ kiểu boolean là gì?

Câu trả lời:


116

Câu trả lời ngắn gọn: có, các giá trị boolean được xử lý như các thực thể 32 bit, nhưng các mảng boolean sử dụng 1 byte cho mỗi phần tử.

Câu trả lời dài hơn: JVM sử dụng một ô ngăn xếp 32 bit, được sử dụng để chứa các biến cục bộ, đối số phương thức và giá trị biểu thức. Các nguyên thủy nhỏ hơn 1 ô sẽ được đệm ra, các nguyên lớn hơn 32 bit (dài và gấp đôi) lấy 2 ô. Kỹ thuật này giảm thiểu số lượng mã opcodes, nhưng có một số tác dụng phụ đặc biệt (chẳng hạn như cần phải che dấu byte).

Các mã nguyên thủy được lưu trữ trong mảng có thể sử dụng ít hơn 32 bit và có các mã quang khác nhau để tải và lưu trữ các giá trị nguyên thủy từ một mảng. Giá trị boolean và byte đều sử dụng mã baloadbastoreopcodes, điều này ngụ ý rằng mảng boolean chiếm 1 byte cho mỗi phần tử.

Theo như cách bố trí đối tượng trong bộ nhớ, điều này được đề cập trong quy tắc "triển khai riêng tư" , nó có thể là 1 bit, 1 byte hoặc như một người đăng khác đã lưu ý, được căn chỉnh theo ranh giới từ kép 64 bit. Rất có thể, nó có kích thước từ cơ bản của phần cứng bên dưới (32 hoặc 64 bit).


Về việc giảm thiểu dung lượng mà boolean sử dụng: nó thực sự không phải là vấn đề đối với hầu hết các ứng dụng. Khung ngăn xếp (chứa các biến cục bộ và đối số phương thức) không lớn lắm và trong lược đồ lớn, boolean rời rạc trong một đối tượng cũng không lớn. Nếu bạn có nhiều đối tượng với nhiều boolean, thì bạn có thể sử dụng các trường bit được quản lý thông qua getters và setters của bạn. Tuy nhiên, bạn sẽ phải trả một hình phạt trong thời gian CPU có thể lớn hơn hình phạt trong bộ nhớ.


Đối với các thành viên lớp boolean / byte, nó cũng đúng, rằng chúng cũng là 4 byte? Cá thể lớp được phân bổ toàn bộ trên ngăn xếp, vì vậy tôi có thể tưởng tượng, JVM có thể nên sử dụng 1 byte cho mỗi thành viên boolean / byte và cuối cùng thực hiện căn chỉnh 4 byte cho cá thể lớp hoàn chỉnh. Có phải vậy không? (nếu bạn có tài liệu tham khảo mà chứng minh điều này, xin vui lòng, chia sẻ)
dma_k

@dma_k: như đã lưu ý trong phản hồi của tôi, bố cục của một cá thể lớp phụ thuộc vào việc triển khai. Tuy nhiên, lưu ý rằng các cá thể lớp không được lưu trữ trong ngăn xếp, chúng được lưu trữ trên heap (mặc dù bạn sẽ thấy một số tham chiếu đến JDK 7 "phân tích thoát" di chuyển các đối tượng từ ngăn xếp sang đống, điều này có vẻ không đúng); xem java.sun.com/javase/7/docs/technotes/guides/vm/…)
kdgregory

1
Đôi khi việc đóng gói boolean có thể thực sự nhanh hơn. Bất cứ khi nào kích thước bộ nhớ cache quan trọng, có thể tốt hơn nên đóng gói mọi thứ. Ví dụ, một sàng nguyên tố được phân đoạn hoạt động theo khối 32 kB (kích thước bộ nhớ đệm L1) nhanh hơn một sàng không phân đoạn. Có một số chi phí giữa các phần và với việc đóng gói, bạn phải trả chi phí ít hơn tám lần thường xuyên. Tôi vẫn chưa đo được.
maaartinus

7

Một boolean đơn lẻ ở đâu đó trong hệ thống phân cấp kế thừa có thể sử dụng tối đa 8 byte! Điều này là do đệm. Có thể tìm thêm chi tiết trong Đối tượng Java của tôi sử dụng bao nhiêu bộ nhớ? :

Quay trở lại câu hỏi một boolean tiêu thụ bao nhiêu, vâng, nó tiêu thụ ít nhất một byte, nhưng do các quy tắc căn chỉnh, nó có thể tiêu thụ nhiều hơn. IMHO sẽ thú vị hơn khi biết rằng boolean [] sẽ sử dụng một byte cho mỗi mục nhập chứ không phải một bit, cộng với một số chi phí do căn chỉnh và cho trường kích thước của mảng. Có các thuật toán đồ thị trong đó các trường bit lớn rất hữu ích và bạn cần lưu ý rằng, nếu bạn sử dụng boolean [], bạn cần bộ nhớ gần như chính xác gấp 8 lần so với thực tế (1 byte so với 1 bit).


Làm thế nào sẽ sử dụng một boolean []?
Thomas Jung

boolean [] có thể được sử dụng cho một mặt nạ. Tuy nhiên, đôi khi BitSet có thể tốt hơn vì nó có một số phương pháp hữu ích.
Michael Munsey

5

Phiên bản thứ 5 của Java trong một Nutshell (O'Reilly) cho biết kiểu nguyên thủy boolean là 1 byte. Điều đó có thể sai, dựa trên những gì kiểm tra đống đang hiển thị. Tôi tự hỏi nếu hầu hết các JVM có vấn đề với việc cấp phát ít hơn một byte cho các biến.


3

Việc ánh xạ boolean được thực hiện với CPU 32bit. Giá trị int có 32 bit nên nó có thể được xử lý trong một thao tác.

Đây là một giải pháp từ Java IAQ của Peter Norvig: Các câu hỏi được trả lời không thường xuyên để đo kích thước (với một số không chính xác):

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.");

Vì cuộc trò chuyện này là về các nguyên thủy, bạn phải sáng tạo trong việc kiểm tra điều này vì các nguyên thủy không được lưu trữ trong heap trừ khi chúng là một trường trên một cá thể hoặc một mảng. Và không ai trong số đó trả lời câu hỏi Java sẽ chọn cách nào để lưu trữ nó trong ngăn xếp.
Jesse

2

CPU hoạt động trên một độ dài kiểu dữ liệu cụ thể. Trong trường hợp CPU 32 bit, chúng dài 32 bit và do đó bạn gọi là 'int' trong Java. Mọi thứ bên dưới hoặc bên trên phải được lấp đầy hoặc chia nhỏ đến độ dài này trước khi CPU có thể xử lý. Điều này không mất nhiều thời gian, nhưng nếu bạn cần 2 chu kỳ CPU thay vì 1 cho các hoạt động cơ bản, điều này có nghĩa là chi phí / lần tăng gấp đôi.

Thông số kỹ thuật này dành riêng cho các CPU 32 bit để chúng có thể xử lý boolean với kiểu dữ liệu gốc của chúng.

Bạn chỉ có thể có một ở đây: tốc độ hoặc bộ nhớ - SUN quyết định tốc độ.


1

Boolean đại diện cho một bit thông tin, nhưng "kích thước" của nó không phải là thứ được xác định chính xác, theo hướng dẫn của Sun Java. Các ký tự boolean chỉ có hai giá trị khả dĩ là true và false. Xem Các kiểu dữ liệu Java để biết chi tiết.


-10

Tại sao không tạo một tệp .java như thế này:

Empty.java

class Empty{
}

và một lớp như thế này:

NotEmpty.java

class NotEmpty{
   boolean b;
}

Biên dịch cả hai và so sánh các tệp .class với một trình chỉnh sửa hex.


5
đây hoàn toàn là một số liệu khác, không liên quan đến việc định cỡ kiểu boolean nguyên thủy trong bộ nhớ.
Joel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.