Không gian cần thiết để giữ mảng số nguyên lớn nhất trong bộ nhớ

Jan 04 2021

Tôi đang xem xét một thuật toán và nó giữ một mảng các số nguyên, kích thước của đầu vào là động. Vì vậy, theo tính toán của tôi, nó có thể mất nhiều như

  integer MAX_VALUE  * int size  = ?   
      2^31 integers  * 4 bytes   = ?
2147483648 integers  * 4 bytes   = 8 Gigabytes

Cách tính này có đúng không? JVM sẽ sử dụng nhiều không gian liền kề này để lưu trữ mảng int hay có những thứ khác mà người ta cần xem xét?

Trả lời

3 Eugene Jan 05 2021 at 01:39

Kích thước lý thuyết của mảng sẽ là:

  • numberOfElementsInTheArray * 4 byte

  • 12 byte tiêu đề ( int[]là một Đối tượng). Trên thực tế, kích thước của tiêu đề phụ thuộc vào cờ bạn đã sử dụng và trên phiên bản JVM mà bạn đang chạy

  • 4 byte để giữ nguyên lengthmảng

  • đệm lót.

Ví dụ: (Tôi sẽ sử dụng JOL cho việc này ):

    int [] x = new int[10];
    for(int i=0;i<10;++i){
        x[i] = 9999;
    }
    System.out.println(GraphLayout.parseInstance((Object)x).toPrintable()); 

sẽ xuất:

 [I@7a81197dd object externals:
      ADDRESS       SIZE TYPE PATH                           VALUE
    70fe45268         56 [I                                  [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999]

Vì vậy, nó có 56 bytes:

  • 40 cho chính các giá trị (10 ints * 4 byte)
  • 12 cho tiêu đề
  • 4 cho chiều dài
  • 0 cho phần đệm

Nếu bạn thay đổi mảng này thành Integer, mọi thứ sẽ thay đổi đáng kể. Integerlà một Đối tượng, vì vậy bạn sẽ lưu trữ một tham chiếu bên trong mảng (có thể là 4hoặc 8byte, tùy thuộc vào UseCompressedOopscờ), cộng với mỗi Integercá thể sẽ yêu cầu 2 tiêu đề (mỗi tiêu đề Integerlà một Đối tượng).

    Integer[] y = new Integer[10];
    for(int i=0;i<10;++i){
        y[i] = 9999;
    }

    System.out.println(GraphLayout.parseInstance((Object)y).toFootprint());

sẽ hiển thị:

   [Ljava.lang.Integer;@369f73a2d footprint:
 COUNT       AVG       SUM   DESCRIPTION
     1        56        56   [Ljava.lang.Integer;
    10        16       160   java.lang.Integer
    11                 216   (total)

Tổng số 216 bytes:

  • 4 byte cho mỗi tham chiếu (tôi đã UseCompressedOopbật), tổng cộng 40 byte
  • 12 byte tiêu đề của mảng
  • Độ dài 4 byte của mảng
  • Khoảng đệm 0 byte

Mỗi tham chiếu từ mảng đó trỏ đến một Integer, mỗi Đối tượng đó sẽ có 16 bytes:

  • 4 byte cho phần bên trong intmà chúng giữ
  • Tiêu đề 12 byte
  • Khoảng đệm 0 byte
1 BasilBourque Jan 04 2021 at 15:23

Kích thước mảng tối đa < Integer.MAX_VALUE

Không, mức tối đa của bạn không chính xác.

Giới hạn về số lượng phần tử trong một mảng trong Java ít hơn một chút so với Integer.MAX_VALUE(2.147.483.647), tùy thuộc vào phiên bản Java, hệ điều hành máy chủ và cách Java được biên dịch. Xem Câu trả lời này của Ivan Mamontov về Câu hỏi, Tại sao tôi không thể tạo một mảng với kích thước lớn? .

Có, mảng lớn nhất là int≈ 8 hợp đồng biểu diễn

Vì vậy, kích thước của một mảng tối đa intsẽ là khoảng ( Integer.MAX_VALUE - 8L ) * 32Lbit là 68,719,476,448 bit là 8,589,934,556 octet.

Vì vậy, có, khoảng 8 hợp đồng biểu diễn bộ nhớ. Và hãy nhớ: đây là bộ nhớ liền kề cho một mảng. Vì thế:

  • Có thể có công việc quan trọng trên một phần của JVM và hệ điều hành chủ để tạo ra một mảng như vậy tùy thuộc vào mức độ phân mảnh của bộ nhớ tại thời điểm đó trong thời gian chạy.
  • Nếu phần cứng máy chủ không có đủ bộ nhớ thực, bạn sẽ chuyển sang bộ nhớ ảo, nơi kết quả phân trang có thể dẫn đến hiệu suất khủng khiếp.

Luôn thực hiện các bài kiểm tra trong thế giới thực nếu bạn thực sự đang đẩy những giới hạn này trong công việc của mình. Và bạn có thể muốn xem xét các triển khai thay thế của Java được thiết kế cho bộ nhớ rất lớn, chẳng hạn như Zing của Azul Systems.