java.lang.OutOfMemoryError: พื้นที่ฮีป Java


97

ฉันได้รับข้อผิดพลาดต่อไปนี้ในการเรียกใช้โปรแกรมมัลติเธรด

java.lang.OutOfMemoryError: Java heap space

ข้อผิดพลาดข้างต้นเกิดขึ้นในหนึ่งในเธรด

  1. ถึงความรู้ของฉันพื้นที่ Heap ถูกครอบครองโดยตัวแปรอินสแตนซ์เท่านั้น หากถูกต้องเหตุใดจึงเกิดข้อผิดพลาดหลังจากทำงานได้ดีในบางครั้งเนื่องจากมีการจัดสรรพื้นที่สำหรับตัวแปรอินสแตนซ์ในขณะที่สร้างวัตถุ

  2. มีวิธีใดในการเพิ่มพื้นที่ฮีปหรือไม่?

  3. ฉันควรทำการเปลี่ยนแปลงอะไรกับโปรแกรมของฉันเพื่อที่จะใช้พื้นที่ฮีปน้อยลง


คำตอบ:


105

หากคุณต้องการเพิ่มพื้นที่ฮีปคุณสามารถใช้java -Xms<initial heap size> -Xmx<maximum heap size>ในบรรทัดคำสั่ง โดยค่าเริ่มต้นค่าต่างๆจะขึ้นอยู่กับเวอร์ชัน JRE และการกำหนดค่าระบบ คุณสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือก VM บนเว็บไซต์ของ

อย่างไรก็ตามฉันขอแนะนำให้ทำโปรไฟล์แอปพลิเคชันของคุณเพื่อหาสาเหตุที่ขนาดฮีปของคุณถูกกิน NetBeans มีโปรไฟล์ที่ดีมากรวมอยู่ด้วย ฉันเชื่อว่ามันใช้jvisualvmใต้ฝากระโปรง ด้วยตัวสร้างโปรไฟล์คุณสามารถลองค้นหาตำแหน่งที่สร้างวัตถุจำนวนมากเมื่อวัตถุได้รับขยะและอื่น ๆ


1
ฉันใช้ Netbeans แต่ไม่รู้วิธีใช้ profiler ฉันต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับผู้สร้างโปรไฟล์เพื่อที่ฉันจะได้ใช้เพื่อค้นหาการรั่วไหลของหน่วยความจำในแอปพลิเคชันของฉัน
Yatendra Goel

ฉันได้เพิ่มลิงก์ไปยังหน้าบนเว็บไซต์ NetBeans ( profiler.netbeans.org ) ซึ่งมีเอกสารที่ดีมากเกี่ยวกับโปรไฟล์ตั้งแต่พื้นฐานไปจนถึงการใช้งานขั้นสูง
Thomas Owens

ค่าเริ่มต้นจะเปลี่ยนไปตามเวอร์ชันจาวาคุณควรใส่ข้อมูลนี้ในคำตอบ
Dariusz

เพิ่งแก้ไขปัญหาที่คล้ายกันและลองครั้งแรก: java -jar division.jar -Xmx512m -Xms512m - สิ่งนี้ทำให้ฉันมีข้อผิดพลาดเหมือนกัน แต่เมื่อฉันทำเช่นนั้น: java -Xmx512m -Xms512m -jar division.jar - ทั้งหมดเรียบร้อยดี ดังนั้นลำดับของพารามิเตอร์ก็สำคัญเช่นกัน
hipokito

อาร์กิวเมนต์ @hipokito หลังจากไฟล์ jar ถูกส่งต่อไปยังเมธอด main () ของไฟล์ jar เป็น args []
Asu

29

1.- ใช่ แต่ค่อนข้างหมายถึงหน่วยความจำทั้งหมดที่ใช้โดยโปรแกรมของคุณ

2.- ใช่ดูตัวเลือก Java VM

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size

ได้แก่

java -Xmx2g กำหนดหน่วยความจำสูงสุด 2 กิกะไบต์ให้กับแอปของคุณ

แต่คุณควรดูว่าคุณไม่มีหน่วยความจำรั่วก่อนหรือไม่

3.- ขึ้นอยู่กับโปรแกรม ลองใช้หน่วยความจำรั่ว คำถามนี้คงยากที่จะตอบ เมื่อเร็ว ๆ นี้คุณสามารถสร้างโปรไฟล์โดยใช้ JConsole เพื่อพยายามค้นหาว่าหน่วยความจำของคุณกำลังจะไปที่ใด


ในขณะที่ (จริง);)
Gal Bracha

8

คุณอาจต้องการดูไซต์นี้เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับหน่วยความจำใน JVM: http://developer.streamezzo.com/content/learn/articles/optimization-heap-memory-usage

ฉันพบว่ามีประโยชน์ในการใช้visualgcเพื่อดูว่าส่วนต่างๆของโมเดลหน่วยความจำเติมเข้าไปอย่างไรเพื่อพิจารณาว่าจะต้องเปลี่ยนแปลงอะไรบ้าง

เป็นการยากที่จะระบุว่าส่วนใดของหน่วยความจำถูกเติมเต็มดังนั้น visualgc เนื่องจากคุณอาจต้องการเพียงแค่เปลี่ยนส่วนที่มีปัญหาแทนที่จะพูดว่า

ละเอียด! ฉันจะให้ RAM 1G กับ JVM

พยายามให้ชัดเจนยิ่งขึ้นเกี่ยวกับสิ่งที่คุณกำลังทำในระยะยาวคุณอาจจะพบว่าโปรแกรมนั้นดีขึ้นสำหรับมัน

ในการตรวจสอบว่าหน่วยความจำรั่วที่ใดคุณสามารถใช้การทดสอบหน่วยสำหรับสิ่งนั้นโดยการทดสอบหน่วยความจำก่อนการทดสอบและหลังจากนั้นและหากมีการเปลี่ยนแปลงใหญ่เกินไปคุณอาจต้องการตรวจสอบ แต่คุณต้อง ทำการตรวจสอบในขณะที่การทดสอบของคุณยังทำงานอยู่



6

คุณสามารถรับขนาดหน่วยความจำฮีปได้จากโปรแกรมด้านล่าง

public class GetHeapSize {
    public static void main(String[] args) {
        long heapsize = Runtime.getRuntime().totalMemory();
        System.out.println("heapsize is :: " + heapsize);
    }
} 

ดังนั้นคุณสามารถเพิ่มขนาดฮีปได้โดยใช้: java -Xmx2g http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html


6
  1. ถึงความรู้ของฉันพื้นที่ Heap ถูกครอบครองโดยตัวแปรอินสแตนซ์เท่านั้น หากถูกต้องเหตุใดจึงเกิดข้อผิดพลาดหลังจากทำงานได้ดีในบางครั้งเนื่องจากมีการจัดสรรพื้นที่สำหรับตัวแปรอินสแตนซ์ในขณะที่สร้างวัตถุ

นั่นหมายความว่าคุณกำลังสร้างวัตถุเพิ่มเติมในแอปพลิเคชันของคุณในช่วงเวลาหนึ่งอย่างต่อเนื่อง วัตถุใหม่จะถูกเก็บไว้ในหน่วยความจำฮีปและนั่นคือสาเหตุของการเติบโตในหน่วยความจำฮีป

ฮีปไม่เพียง แต่มีตัวแปรอินสแตนซ์ มันจะจัดเก็บชนิดข้อมูลที่ไม่ใช่พื้นฐาน (Objects) ทั้งหมด อายุการใช้งานของวัตถุเหล่านี้อาจสั้น (บล็อกวิธีการ) หรือยาว (จนกว่าวัตถุจะถูกอ้างอิงในแอปพลิเคชันของคุณ)

  1. มีวิธีใดในการเพิ่มพื้นที่ฮีปหรือไม่?

ใช่. ดูบทความ Oracle นี้เพื่อดูรายละเอียดเพิ่มเติม

มีพารามิเตอร์สองตัวสำหรับการตั้งค่าขนาดฮีป:

-Xms:ซึ่งกำหนดขนาดฮีปเริ่มต้นและต่ำสุด

-Xmx:ซึ่งกำหนดขนาดฮีปสูงสุด

  1. ฉันควรทำการเปลี่ยนแปลงอะไรกับโปรแกรมของฉันเพื่อที่จะใช้พื้นที่ฮีปน้อยลง

ขึ้นอยู่กับใบสมัครของคุณ

  1. ตั้งค่าหน่วยความจำฮีปสูงสุดตามความต้องการของแอปพลิเคชันของคุณ

  2. อย่าทำให้หน่วยความจำรั่วไหลในแอปพลิเคชันของคุณ

  3. หากคุณพบการรั่วไหลของหน่วยความจำในแอปพลิเคชันของคุณให้ค้นหาสาเหตุที่แท้จริงด้วยความช่วยเหลือของเครื่องมือสร้างโปรไฟล์เช่นMAT , Visual VM , jconsoleเป็นต้นเมื่อคุณพบสาเหตุที่แท้จริงแล้วให้แก้ไขการรั่วไหล

หมายเหตุสำคัญจากบทความ oracle

สาเหตุ: ข้อความรายละเอียดพื้นที่ฮีป Java ระบุว่าไม่สามารถจัดสรรอ็อบเจ็กต์ในฮีป Java ได้ ข้อผิดพลาดนี้ไม่ได้หมายความว่าหน่วยความจำรั่วเสมอไป

สาเหตุที่เป็นไปได้:

  1. การกำหนดค่าที่ไม่เหมาะสม (ไม่ได้จัดสรรหน่วยความจำที่เพียงพอ)
  2. แอ็พพลิเคชันถือการอ้างอิงถึงอ็อบเจ็กต์โดยไม่ได้ตั้งใจและป้องกันไม่ให้อ็อบเจ็กต์ถูกเก็บรวบรวม
  3. แอปพลิเคชันที่ใช้โปรแกรมสุดท้ายมากเกินไป หากคลาสมีวิธีการสรุปวัตถุประเภทนั้นจะไม่มีการเรียกคืนพื้นที่ในเวลารวบรวมขยะ ถ้าด้าย finalizer ไม่สามารถให้ทันกับคิวสรุปแล้วกอง Java สามารถเติมและชนิดของข้อยกเว้น OutOfMemoryError นี้จะถูกโยน

ในบันทึกอื่นให้ใช้อัลกอริทึมการรวบรวมขยะที่ดีกว่า ( CMSหรือG1GC )

ลองดูคำถามนี้เพื่อทำความเข้าใจ G1GC


5
  1. ในกรณีส่วนใหญ่โค้ดจะไม่ได้รับการปรับให้เหมาะสม ปล่อยวัตถุเหล่านั้นที่คุณคิดว่าไม่จำเป็นต้องใช้ต่อไป หลีกเลี่ยงการสร้างวัตถุในวงของคุณทุกครั้ง พยายามใช้แคช ฉันไม่รู้ว่าใบสมัครของคุณเป็นอย่างไร แต่ในการเขียนโปรแกรมกฎข้อหนึ่งของชีวิตปกติก็ใช้ได้เช่นกัน

    การป้องกันดีกว่าการรักษา "อย่าสร้างวัตถุที่ไม่จำเป็น"


3
  1. ตัวแปรโลคัลจะอยู่บนสแตก พื้นที่กองซ้อนถูกครอบครองโดยวัตถุ

  2. คุณสามารถใช้-Xmxตัวเลือก

  3. โดยทั่วไปพื้นที่ฮีปจะถูกใช้จนหมดทุกครั้งที่คุณจัดสรรวัตถุใหม่ด้วย newและปล่อยให้เป็นอิสระหลังจากที่อ็อบเจ็กต์ไม่ได้รับการอ้างอิงอีกต่อไป ดังนั้นอย่าให้มีการอ้างอิงถึงวัตถุที่คุณไม่ต้องการอีกต่อไป


1

ไม่ฉันคิดว่าคุณกำลังคิดถึงพื้นที่สแต็ก พื้นที่กองซ้อนถูกครอบครองโดยวัตถุ วิธีเพิ่มมันคือ -Xmx256m แทนที่ 256 ด้วยจำนวนที่คุณต้องการในบรรทัดคำสั่ง


1

เพื่อหลีกเลี่ยงข้อยกเว้นนั้นหากคุณใช้ JUnit และ Spring ให้ลองเพิ่มสิ่งนี้ในทุกคลาสทดสอบ:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)

0

ใน netbeans ไปที่แถบเครื่องมือ 'Run' -> 'Set Project Configuration' -> 'Customize' -> 'run' ของหน้าต่างที่โผล่ขึ้นมา -> 'VM Option' -> เติม '-Xms2048m -Xmx2048m '. สามารถแก้ปัญหาขนาดฮีปได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.