Tại sao lớp Integer lưu các giá trị trong phạm vi -128 đến 127?


81

Về Câu hỏi trước của tôi, Tại sao so sánh == với Integer.valueOf (Chuỗi) cho kết quả khác nhau cho 127 và 128? , chúng tôi biết rằng Integer classcó một bộ nhớ cache lưu trữ các giá trị giữa -128127.

Chỉ cần tự hỏi, tại sao giữa -128 và 127 ?

Tài liệu Integer.valueOf () cho biết rằng nó " lưu vào bộ nhớ đệm các giá trị được yêu cầu thường xuyên " . Nhưng liệu các giá trị giữa -128127thường được yêu cầu có thực không? Tôi nghĩ rằng các giá trị được yêu cầu thường xuyên là rất chủ quan.
Có bất kỳ lý do có thể nào đằng sau điều này?

Từ tài liệu cũng nêu rõ: " .. và có thể lưu vào bộ nhớ cache các giá trị khác ngoài phạm vi này. "
Làm cách nào để đạt được điều này?


7
Xem lại tài liệu: Oracle chỉ đang che giấu các lỗi của họ trong trường hợp họ quyết định thay đổi hành vi sau đó. Ví dụ: họ có thể quyết định rằng Java 9 sẽ lưu vào bộ đệm từ -1024 đến 1023. Thông báo là, đừng dựa vào bộ đệm chứa hoặc không chứa bất kỳ số nguyên cụ thể nào.
Dawood ibn Kareem

7
Tôi giả sử bạn lặp lại thường xuyên hơn từ 0 đến X so với từ 13476 đến Y. Chắc hẳn họ đã quyết định rằng các giá trị âm cũng nên được bao gồm và -128 -> 127 có ý nghĩa đối với byte có dấu.
Jeroen Vannevel

2
Không phải lặp đi lặp lại hầu như luôn luôn được thực hiện với các int nguyên thủy - không phải Số nguyên đóng hộp? Bộ nhớ đệm không áp dụng.
bradvido

2
Bộ nhớ cache hoàn toàn là một thứ hiệu suất. Miễn là nó không tạo ra vấn đề hiệu suất cho bạn, bạn không nên quan tâm đến phạm vi nào được lưu trong bộ nhớ cache. (Nó sẽ là đỉnh điểm của sự điên rồ để xây dựng thành mã của bạn một sự phụ thuộc vào Integer bộ nhớ đệm.)
Hot Licks

3
@JohnR nó nằm trong thông số kỹ thuật của Ngôn ngữ Java, hãy xem câu trả lời của assylias bên dưới.
Zac Thompson

Câu trả lời:


105

Chỉ cần tự hỏi, tại sao giữa -128 và 127?

Một loạt các số nguyên lớn hơn có thể được lưu vào bộ nhớ cache, nhưng ít nhất những số từ -128 đến 127 phải được lưu vào bộ nhớ cache vì nó được Đặc tả ngôn ngữ Java yêu cầu (tôi nhấn mạnh):

Nếu giá trị p đang được đóng hộp là true, false, một byte hoặc một ký tự trong phạm vi \ u0000 đến \ u007f, hoặc một số int hoặc số ngắn trong khoảng -128 đến 127 (bao gồm) , thì r1 và r2 là kết quả của bất kỳ hai chuyển đổi quyền anh của p. Nó luôn luôn là trường hợp r1 == r2.

Cơ sở lý luận cho yêu cầu này được giải thích trong cùng một đoạn:

Lý tưởng nhất, quyền anh một giá trị nguyên thủy nhất định p, sẽ luôn mang lại một tham chiếu giống hệt nhau . Trong thực tế, điều này có thể không khả thi nếu sử dụng các kỹ thuật triển khai hiện có. Các quy tắc trên là một thỏa hiệp thực dụng. Mệnh đề cuối cùng ở trên yêu cầu các giá trị chung nhất định luôn được đóng hộp thành các đối tượng không thể phân biệt được. [...]

Điều này đảm bảo rằng trong hầu hết các trường hợp phổ biến, hành vi sẽ là hành vi mong muốn, mà không áp dụng hình phạt hiệu suất quá mức, đặc biệt là trên các thiết bị nhỏ . Ví dụ: các triển khai giới hạn bộ nhớ ít hơn có thể lưu vào bộ nhớ cache tất cả các giá trị char và short, cũng như các giá trị int và long trong phạm vi -32K đến + 32K.


Làm cách nào để lưu vào bộ nhớ cache các giá trị khác ngoài phạm vi này.?

Bạn có thể sử dụng -XX:AutoBoxCacheMaxtùy chọn JVM, tùy chọn này không thực sự được ghi lại trong danh sách Tùy chọn JVM của điểm phát sóng hiện có . Tuy nhiên, nó được đề cập trong các nhận xét bên trong Integerlớp xung quanh dòng 590 :

Kích thước của bộ nhớ cache có thể được kiểm soát bởi -XX:AutoBoxCacheMax=<size>tùy chọn.

Lưu ý rằng đây là cách triển khai cụ thể và có thể có hoặc không có sẵn trên các JVM khác.


2
Đây là câu trả lời đầy đủ và tốt nhất - câu hỏi gây nhầm lẫn giữa phạm vi -128 đến 127 với "các giá trị thường được yêu cầu", trong khi thực tế chúng là vì những lý do khác nhau. -128 đến 127 được lưu vào bộ nhớ đệm cho quyền anh. "các giá trị được yêu cầu thường xuyên" được lưu vào bộ nhớ đệm để đạt hiệu suất.
Zac Thompson

@ZacThompson, cảm ơn bạn đã chỉ ra điều này. Nhận xét trước đây của tôi không đúng. Cụm từ khóa từ thông số kỹ thuật là "một int ... từ -128 đến 127 (bao gồm), sau đó đặt r1 và r2 là kết quả của hai chuyển đổi quyền anh bất kỳ của p. Nó luôn luôn là trường hợp r1 == r2." Vì vậy, nếu tôi hiểu đúng, các nhiệm vụ spec mà Integer.valueOf (X) == Integer.valueOf (X), nơi -128 <= X <= 127.
John R

Đây là câu trả lời duy nhất cho phần "tại sao" của câu hỏi cung cấp một cái gì đó khác với "nó là mặc định". Tuy nhiên, câu trả lời này không hoàn chỉnh vì nó không giải quyết được phần "như thế nào" của câu hỏi. Tham khảo phản hồi của những người khác trên XX: AutoBoxCacheMax và thêm thông tin về cách kiểm soát hành vi lưu vào bộ nhớ đệm trên các triển khai khác của JVM (hoặc cho biết triển khai JVM nào có các tùy chọn để kiểm soát hành vi này) sẽ làm cho câu trả lời này hoàn chỉnh.
John R

"Trong thực tế, điều này có thể không khả thi nếu sử dụng các kỹ thuật triển khai hiện có." Tôi không thể nhận được dòng này. Bạn có thể vui lòng giải thích nó?
niiraj874u

2
@ niiraj874u Việc triển khai hiện tại sử dụng một bộ đệm ẩn nằm trong bộ nhớ - mỗi số nguyên "chuẩn" được giữ trong bộ đệm đó. Vì vậy, lưu vào bộ nhớ đệm tất cả các số nguyên có nghĩa là bạn có thể phải chứa tới 2 ^ 32 số nguyên (= 15+ GB) trong bộ nhớ, điều này là không hợp lý, ngay cả trên một máy tính để bàn hiện đại.
assylias

22

-128 đến 127 là kích thước mặc định. Nhưng javadoc cũng nói rằng kích thước của bộ nhớ cache Integer có thể được kiểm soát bởi -XX:AutoBoxCacheMax=<size>tùy chọn. Lưu ý rằng nó chỉ đặt giá trị cao, giá trị thấp luôn là -128. Tính năng này đã được giới thiệu trong 1.6.

Đối với lý do tại sao -128 đến 127 - đây là dải giá trị byte và việc sử dụng nó cho một bộ nhớ cache rất nhỏ là điều đương nhiên.


làm thế nào chúng ta có thể thực hiện -XX:AutoBoxCacheMax=<size>?
DnR

chạy java -XX: AutoBoxCacheMax = 256 ... và bạn sẽ thấy rằng Integer.valueOf (256) == Integer.valueOf (256)
Evgeniy Dorofeev

bằng cách chạy java -XX:AutoBoxCacheMax=256trong bảng điều khiển, tôi đã nhậnError:could not create the Java Virtual Machine
DnR

thử java -version nó phải được 1.6 hoặc cao hơn, 1,7 tác phẩm của tôi OK
Evgeniy Dorofeev

2
Đúng vậy, đây là lý do tại sao javadoc nói ..may được kiểm soát ... Java của tôi là 64 bit
Evgeniy Dorofeev

5

Lý do để lưu vào bộ nhớ đệm các số nguyên nhỏ, nếu đó là những gì bạn đang hỏi, là nhiều thuật toán sử dụng các số nguyên nhỏ trong tính toán của chúng, vì vậy việc tránh chi phí tạo đối tượng cho các giá trị này có xu hướng đáng giá.

Sau đó, câu hỏi sẽ trở thành Số nguyên nào để lưu vào bộ nhớ cache. Một lần nữa, nói chung, tần suất sử dụng các giá trị không đổi có xu hướng giảm khi giá trị tuyệt đối của hằng số tăng lên - mọi người đều dành nhiều thời gian để sử dụng các giá trị 1 hoặc 2 hoặc 10, tương đối ít sử dụng giá trị 109. thâm thúy; ít hơn sẽ có hiệu suất phụ thuộc vào tốc độ người ta có thể có được Số nguyên cho 722 .. Java đã chọn phân bổ 256 vị trí trong phạm vi của giá trị byte có dấu. Quyết định này có thể đã được thông báo bằng cách phân tích các chương trình đang tồn tại vào thời điểm đó, nhưng cũng có khả năng là một quyết định hoàn toàn tùy ý. Đó là một khoảng không gian hợp lý để đầu tư, nó có thể được truy cập nhanh chóng (mặt nạ để tìm xem giá trị có nằm trong phạm vi của bộ đệm hay không, sau đó tra cứu bảng nhanh để truy cập bộ nhớ cache) và nó chắc chắn sẽ bao gồm các trường hợp phổ biến nhất.

Nói cách khác, tôi nghĩ câu trả lời cho câu hỏi của bạn là "nó không chủ quan như bạn nghĩ, nhưng giới hạn chính xác phần lớn là một quyết định mang tính nguyên tắc ... và bằng chứng thực nghiệm cho thấy nó đã đủ tốt. "


3

Giá trị số nguyên cao nhất có thể được lưu vào bộ nhớ cache có thể được định cấu hình thông qua thuộc tính hệ thống tức là java.lang.Integer.IntegerCache.high( -XX:AutoBoxCacheMax). Bộ nhớ cache được thực hiện bằng cách sử dụng một mảng.

    private static class IntegerCache {
    static final int high;
    static final Integer cache[];

    static {
        final int low = -128;

        // high value may be configured by property
        int h = 127;
        if (integerCacheHighPropValue != null) {
            // Use Long.decode here to avoid invoking methods that
            // require Integer's autoboxing cache to be initialized
            int i = Long.decode(integerCacheHighPropValue).intValue();
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - -low);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

    private IntegerCache() {}
}

0

Khi bạn gặp phải lớp Integer và luôn được đóng hộp trong phạm vi -128 đến 127, tốt hơn hết bạn nên chuyển đổi đối tượng Integer thành giá trị int như bên dưới.

<Your Integer Object>.intValue()
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.