JVM ไม่อยู่ในหน่วยความจำสาเหตุ
คำถามอ้างอิงจาก Oracle Hotspot JDK8
เมื่อแอปพลิเคชันพบjava.lang.OutOfMemory: Java heap space
ข้อยกเว้นฉันคิดว่ามีเหตุผลสองประการที่เป็นไปได้
- ขนาดฮีป JVM ที่จัดสรรถึงขนาดที่
-Xmx
กำหนดและระบบ GC ไม่สามารถบีบพื้นที่ได้เพียงพอ - ฮีป JVM ที่จัดสรรไม่สามารถเข้าถึงได้
-Xmx
แต่มีหน่วยความจำกายภาพไม่เพียงพอสำหรับฮีป JVM ที่จะเติบโต สมมติว่า-Xms
<-Xmx
.
ฉันรู้ว่า1
เป็นเหตุผลให้ JVM ยกเลิกjava.lang.OutOfMemory: Java heap space
ข้อยกเว้น เป็น2
เหตุผลหนึ่งสาเหตุ?
ฉันพบบางบทความที่กล่าวถึงjava.lang.OutOfMemoryError: native memory exhausted
แต่ทั้งหมดนี้ จำกัด อยู่ที่เว็บไซต์ IBM Expetion นี้ จำกัด เฉพาะ IBM ที่ใช้ JVM หรือเป็นค่า expetion มาตรฐานในข้อกำหนด JVM?
ฉันทำการทดลองบางอย่างกับโค้ดที่ @Eugene ให้มาในคำตอบ ดังที่ @Holger ตั้งข้อสังเกตว่าผลลัพธ์แตกต่างกันไปในสภาพแวดล้อมที่แตกต่างกัน ฉันทดสอบทั้งบน CentOS x64 และ Win7 x64 ด้วย Hotspot JDK8 x64 เพื่อความเรียบง่ายการสลับและหน่วยความจำเสมือนถูกปิดใช้งาน
ฉันเพิ่มขอบเขตหน่วยความจำ (-Xmx และ -Xms) ทีละขั้นตอน
I. -Xmx < หน่วยความจำลอจิกที่ใช้ได้
- ทั้งบน CentOS และ Windows จะแสดงOutOfMemoryError: Java heap space
II. หน่วยความจำลอจิกที่ใช้ได้ <-Xmx < หน่วยความจำกายภาพสูงสุด
- CentOS: GC พยายามใช้เวลาให้บริการ GC เต็มรูปแบบด้วยการจัดสรรล้มเหลวและกระบวนการจะถูกฆ่าโดยระบบโดยทิ้งข้อความไว้ว่าถูกฆ่า
- Windows: GC พยายามใช้เวลาให้บริการ GC เต็มรูปแบบพร้อมด้วยAllocation Failureและทิ้งOutOfMemoryError: Java heap space
สาม. -Xmx> หน่วยความจำกายภาพสูงสุด
- CentOS: เหมือนกับใน II
- Windows: เหมือนกับใน II
IV. -Xms> หน่วยความจำกายภาพสูงสุด
- CentOS: JVM ดูเหมือนจะไม่สามารถเริ่มต้นได้ ข้อความแสดงข้อผิดพลาดเป็นดังนี้:
คำเตือน Java HotSpot (TM) 64-Bit Server VM: INFO: os :: commit_memory (0x00000000e62a0000, 349569024, 0) ล้มเหลว ข้อผิดพลาด = 'ไม่สามารถจัดสรรหน่วยความจำได้' (errno = 12)
- Windows: JVM ไม่สามารถเริ่มทำงานได้ ข้อความแสดงข้อผิดพลาดเป็นดังนี้:
เกิดข้อผิดพลาดระหว่างการเริ่มต้น VM ไม่สามารถจองพื้นที่เพียงพอสำหรับฮีปวัตถุ
ดังนั้น JVM เดียวกันจึงทำงานแตกต่างกันใน OS ที่แตกต่างกัน
- บน windows ระบบปฏิบัติการจะไม่ฆ่า JVM และ JVM จะโยนOutOfMemoryError: Java heap space เสมอเมื่อการใช้งานหน่วยความจำเพิ่มขึ้น
- บน Linux ระบบปฏิบัติการจะฆ่าเมื่อมีหน่วยความจำไม่เพียงพอ
- บน OS JVM ทั้งสองล้มเหลวในการเริ่มทำงานเมื่อหน่วยความจำที่มีอยู่ไม่เป็นไปตามข้อกำหนดขั้นต่ำของ JVM
คำตอบ
ประการแรกมีสาเหตุมากกว่าที่ GC จะล้มเหลวโดย "หน่วยความจำไม่เพียงพอ" ตามที่ความคิดเห็นในคำถามของคุณอธิบาย
การพิสูจน์หมายเลขจุด (2) เป็นเรื่องง่ายเพียงสร้างรหัสที่จัดสรรไว้เสมอ:
public static void main(String[] args) {
test(1);
}
static void test(int x){
List<byte[]> list = new ArrayList<>();
while(x == 1){
byte [] b =new byte[1 * 1024 * 1024];
b[100] = 42;
list.add(b);
}
System.out.println(list.hashCode());
}
และรันสิ่งนี้ด้วย-Xms1g -Xmx100g
ระบบที่มี100g
RAM น้อยกว่า คุณสามารถเปิดใช้งานบันทึก GC (เช่นฉันทำ"-Xlog:heap*=debug" "-Xlog:gc*=debug"
ในแฟล็ก java-9) และดูว่า GC พยายามจัดการกับการจัดสรรคงที่นี้ยากเพียงใดในที่สุดก็ล้มเหลว