พื้นที่ที่ต้องการเพื่อเก็บอาร์เรย์จำนวนเต็มมากที่สุดในหน่วยความจำ

Jan 04 2021

ฉันกำลังตรวจสอบอัลกอริทึมและเก็บอาร์เรย์ของจำนวนเต็มขนาดของอินพุตเป็นแบบไดนามิก ดังนั้นจากการคำนวณของฉันอาจใช้เวลามากถึง

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

การคำนวณนี้ถูกต้องหรือไม่? JVM จะใช้พื้นที่ที่ต่อเนื่องกันมากขนาดนี้เพื่อจัดเก็บ int array หรือมีสิ่งอื่นที่ต้องพิจารณาหรือไม่?

คำตอบ

3 Eugene Jan 05 2021 at 01:39

ขนาดตามทฤษฎีของอาร์เรย์จะเป็น:

  • numberOfElementsInTheArray * 4 ไบต์

  • ส่วนหัว 12 ไบต์ ( int[]เป็นวัตถุ) จริงๆแล้วขนาดของส่วนหัวขึ้นอยู่กับแฟล็กที่คุณใช้และบนเวอร์ชัน JVM ที่คุณกำลังเรียกใช้

  • 4 ไบต์เพื่อเก็บlengthอาร์เรย์

  • การขยายความ.

ตัวอย่างเช่น: (ฉันจะใช้JOL สำหรับสิ่งนี้ ):

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

จะส่งออก:

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

ดังนั้นจึงมี56 bytes:

  • 40 สำหรับค่าเอง (10 ints * 4 bytes)
  • 12 สำหรับส่วนหัว
  • 4 สำหรับความยาว
  • 0 สำหรับช่องว่างภายใน

หากคุณเปลี่ยนอาร์เรย์นี้Integerสิ่งต่างๆจะเปลี่ยนไปอย่างมาก Integerเป็นวัตถุดังนั้นคุณจะจัดเก็บการอ้างอิงภายในอาร์เรย์ (ซึ่งอาจเป็น4หรือ8ไบต์ขึ้นอยู่กับUseCompressedOopsแฟล็ก) บวกกับแต่ละIntegerอินสแตนซ์จะต้องมี 2 ส่วนหัว (แต่ละส่วนIntegerคือวัตถุ)

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

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

ซึ่งจะแสดง:

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

ทั้งหมด216 bytes:

  • 4 ไบต์สำหรับการอ้างอิงแต่ละรายการ (ฉันUseCompressedOopเปิดอยู่) รวม 40 ไบต์
  • 12 ไบต์ส่วนหัวของอาร์เรย์
  • ความยาว 4 ไบต์ของอาร์เรย์
  • ช่องว่างภายใน 0 ไบต์

การอ้างอิงแต่ละรายการจากอาร์เรย์นั้นชี้ไปIntegerที่อ็อบเจ็กต์แต่ละตัวจะมี16 bytes:

  • 4 ไบต์สำหรับด้านในintถือ
  • ส่วนหัว 12 ไบต์
  • ช่องว่างภายใน 0 ไบต์
1 BasilBourque Jan 04 2021 at 15:23

ขนาดอาร์เรย์สูงสุด < Integer.MAX_VALUE

ไม่สูงสุดของคุณไม่ถูกต้อง

ขีด จำกัด ของจำนวนองค์ประกอบในอาร์เรย์ใน Java นั้นน้อยกว่าInteger.MAX_VALUE(2,147,483,647) เล็กน้อยขึ้นอยู่กับเวอร์ชันของ Java ระบบปฏิบัติการโฮสต์และวิธีการคอมไพล์ Java ดูคำตอบนี้โดย Ivan Mamontov ในคำถามทำไมฉันไม่สามารถสร้างอาร์เรย์ที่มีขนาดใหญ่ได้ .

ใช่อาร์เรย์ที่ใหญ่ที่สุดint≈ 8 กิ๊ก

ดังนั้นขนาดของอาร์เรย์สูงสุดintจะเป็น( Integer.MAX_VALUE - 8L ) * 32Lบิตประมาณ68,719,476,448 บิตซึ่งเป็น 8,589,934,556 อ็อกเทต

ใช่แล้วหน่วยความจำประมาณ 8 กิ๊ก และจำไว้ว่านี่คือหน่วยความจำที่ต่อเนื่องกันสำหรับอาร์เรย์ ดังนั้น:

  • อาจมีงานสำคัญในส่วนของJVMและโฮสต์ OS เพื่อสร้างอาร์เรย์ดังกล่าวขึ้นอยู่กับว่าหน่วยความจำที่แยกส่วนในขณะนั้นระหว่างรันไทม์นั้นเป็นอย่างไร
  • หากฮาร์ดแวร์ของโฮสต์มีหน่วยความจำจริงไม่เพียงพอคุณจะเข้าสู่หน่วยความจำเสมือนจริงซึ่งการแบ่งหน้าผลลัพธ์อาจทำให้ประสิทธิภาพแย่ลง

ทำการทดสอบในโลกแห่งความเป็นจริงเสมอหากคุณกำลังผลักดันขีด จำกัด เหล่านี้ในงานของคุณจริงๆ และคุณอาจต้องการพิจารณาการใช้งานทางเลือกของ Java ที่ออกแบบมาสำหรับหน่วยความจำขนาดใหญ่มากเช่นZingโดย Azul Systems