กอง Java ใช้ในการจัดเก็บอินสแตนซ์วัตถุ ดังนั้นหากเราสร้างวัตถุอย่างต่อเนื่องและตรวจสอบให้แน่ใจว่ามีเส้นทางที่เข้าถึงได้ระหว่างราก GC และวัตถุที่สร้างขึ้นเพื่อหลีกเลี่ยงวัตถุที่ถูกเก็บรวบรวมขยะจากนั้นเมื่อมีการสร้างวัตถุมากเกินไปมันจะทำให้หน่วยความจำกองไม่เพียงพอ
/** * @author xiongyongshun * vm args: java -xms10m -xmx10m -xx:+heapdumponoutofMemoryError */ชั้นเรียนสาธารณะ outofMemoryErrortest {โมฆะคงที่สาธารณะ int i = 0; ในขณะที่ (จริง) {list.add (i ++); -ข้างต้นเป็นรหัสที่ยกข้อยกเว้น outofmemoryError เราจะเห็นว่ามันป้องกันไม่ให้วัตถุถูกเก็บรวบรวมโดยการสร้างและบันทึกวัตถุอย่างต่อเนื่องในรายการ ดังนั้นเมื่อมีวัตถุมากเกินไปหน่วยความจำกองจะล้น
ผ่าน java -xms10m -xmx10m -xx:+heapdumponoutofmemoryerror เราตั้งค่าหน่วยความจำฮีปเป็น 10 megabytes และใช้พารามิเตอร์ -xx:+heapdumponoutofmemory error เพื่อทำการวิเคราะห์ JVM
หลังจากรวบรวมและเรียกใช้รหัสด้านบนเอาต์พุตต่อไปนี้จะเป็น:
>>> java -xms10m -xmx10m -xx:+heapdumponoutofmemory error com.test.outofmemoryerrortest 16-10-02 23: 35java.lang.outofMemoryError: Java Heap Heap -humping Heap 0.125 วินาที] ข้อยกเว้นในด้าย "หลัก" java.lang.outofmemoryError: พื้นที่ java heap ที่ java.util.arrays.copyof (arrays.java:3210) ที่ java.util.arrays.copyof (Arrays.java:3181) ที่ java.util.arraylist.ensureexplicitcapacity (arraylist.java:235) ที่ java.util.arraylist.ensurecapacityinternal (arraylist.java:227) ที่ java.util.arraylist.add com.test.outofmemoryerrortest.main (outofmemoryerrortest.java:15)
Java Stackoverflowerror
เรารู้ว่ามีพื้นที่หน่วยความจำที่เรียกว่าสแต็กเครื่องเสมือนในพื้นที่ข้อมูลรันไทม์ของ JVM ฟังก์ชั่นของพื้นที่นี้คือ: แต่ละวิธีจะสร้างเฟรมสแต็กเมื่อดำเนินการซึ่งใช้ในการจัดเก็บข้อมูลเช่นตารางตัวแปรท้องถิ่น, ตัวถูกดำเนินการสแต็ก, เมธอดทางออก ฯลฯ
ดังนั้นเราสามารถสร้างการโทรแบบเรียกซ้ำซ้ำได้อย่างไม่ จำกัด เมื่อความลึกแบบเรียกซ้ำมีขนาดใหญ่เกินไปพื้นที่สแต็กจะหมดลงซึ่งจะนำไปสู่ข้อยกเว้น stackoverflowerror
นี่คือรหัสเฉพาะ:
/** * @author xiongyongshun * vm args: java -xss64k */คลาสสาธารณะ outofmemoryerrortest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {stackoutofmemoryError (1); } โมฆะคงที่สาธารณะ stackoutofMemoryError (ความลึก int) {ความลึก ++; StackoutofMemoryError (ความลึก); -หลังจากรวบรวมและเรียกใช้รหัสด้านบนข้อมูลข้อยกเว้นต่อไปนี้จะถูกส่งออก:
ข้อยกเว้นใน Thread "Main" Java.lang.stackoverflowerror ที่ com.test.outofmemoryerrortest.stackoutofmemoryError (outofMemoryerRortest.java:27)
หน่วยความจำล้นในพื้นที่วิธีการ
โปรดทราบว่าเนื่องจาก JDK8 ได้ลบรุ่นถาวรและแทนที่ด้วย metaspace ใน JDK8 ทั้งสองตัวอย่างต่อไปนี้จะไม่ทำให้ java.lang.outofmemoryError: ข้อยกเว้นพื้นที่ Permgen
สระว่ายน้ำคงที่ในระหว่างการรันไทม์
ใน Java 1.6 และรุ่นก่อนหน้าของ Hotspot JVM มีแนวคิดของรุ่นถาวรนั่นคือกลไกการรวบรวมการสร้างของ GC จะขยายไปยังพื้นที่วิธีการ ในพื้นที่วิธีการส่วนหนึ่งของหน่วยความจำใช้ในการจัดเก็บพูลคงที่ ดังนั้นหากมีค่าคงที่มากเกินไปในรหัสหน่วยความจำของพูลคงที่จะหมดลงส่งผลให้หน่วยความจำล้น ดังนั้นจะเพิ่มค่าคงที่จำนวนมากลงในสระคงที่? ในเวลานี้คุณต้องพึ่งพาเมธอด string.intern () ฟังก์ชั่นของวิธี string.intern () คือ: หากค่าของสตริงนี้มีอยู่แล้วในพูลคงที่วิธีนี้จะส่งคืนการอ้างอิงไปยังสตริงที่เกี่ยวข้องในพูลคงที่; มิฉะนั้นเพิ่มค่าที่มีอยู่ในสตริงนี้ไปยังพูลคงที่และส่งคืนการอ้างอิงไปยังวัตถุสตริงนี้ ใน JDK 1.6 และรุ่นก่อนหน้าสระว่ายน้ำคงที่จะถูกจัดสรรในรุ่นถาวร ดังนั้นเราสามารถ จำกัด ขนาดของพูลคงที่ทางอ้อมโดยการตั้งค่าพารามิเตอร์ "-xx: permsize" และ "-xx: maxpermsize"
โปรดทราบว่าการแจกแจงหน่วยความจำของเมธอด string.intern () ที่กล่าวถึงข้างต้นและพูลคงที่สำหรับ JDK 1.6 และเวอร์ชันก่อนหน้าเท่านั้น ใน JDK 1.7 หรือสูงกว่าเค้าโครงหน่วยความจำแตกต่างกันเล็กน้อยเนื่องจากแนวคิดของการสร้างถาวรจะถูกลบออก
ต่อไปนี้เป็นตัวอย่างของรหัสเพื่อใช้หน่วยความจำล้นของพูลคงที่:
/** * @author xiongyongshun * vm args: -xx: permsize = 10m -xx: maxpermsize = 10m */คลาสสาธารณะ runtimeconstantpooloomtest {โมฆะสาธารณะคง int i = 0; ในขณะที่ (จริง) {list.add (string.valueof (i ++). intern ()); -เราเห็นว่าในตัวอย่างนี้มันใช้วิธี String.intern () อย่างแม่นยำเพื่อเพิ่มค่าคงที่สตริงจำนวนมากลงในพูลคงที่ซึ่งนำไปสู่หน่วยความจำล้นของพูลคงที่
เรารวบรวมและเรียกใช้รหัสด้านบนผ่าน JDK1.6 และผลลัพธ์ต่อไปนี้จะเป็น:
ข้อยกเว้นในเธรด "หลัก" java.lang.outofmemoryError: พื้นที่ permgen ที่ java.lang.string.intern (วิธีการดั้งเดิม) ที่ com.test.runtimeconstantpooloomtest.main (runtimeconstantpooloomtest.java:16)
ควรสังเกตว่าหากมีการรวบรวมรหัสข้างต้นและเรียกใช้ผ่าน JDK1.8 จะมีคำเตือนต่อไปนี้และจะไม่มีการสร้างข้อยกเว้น:
>>> java -xx: permsize = 10m -xx: maxpermsize = 10m com.test.runtimeconstantpooloomtest 16-10-03 0: 23java ฮอตสปอต (TM) เซิร์ฟเวอร์ 64 บิต VM คำเตือน: การละเว้นตัวเลือก การสนับสนุนถูกลบออกใน 8.0 Java Hotspot (TM) คำเตือน VM เซิร์ฟเวอร์ 64 บิต: การละเว้นตัวเลือก maxpermsize = 10m; การสนับสนุนถูกลบออกใน 8.0
หน่วยความจำล้นในพื้นที่วิธีการ
ฟังก์ชั่นของพื้นที่เมธอดคือการจัดเก็บข้อมูลที่เกี่ยวข้องของคลาสเช่นชื่อคลาสตัวดัดแปลงการเข้าถึงคลาสคำอธิบายฟิลด์คำอธิบายวิธี ฯลฯ ดังนั้นหากพื้นที่วิธีการมีขนาดเล็กเกินไปและมีการโหลดคลาสมากเกินไปหน่วยความจำล้นของพื้นที่เมธอด
// vm args: -xx: permsize = 10m -xx: maxpermsize = 10mpublic methodareaoomtest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ในขณะที่ (จริง) enhancer.setsuperclass (MethodareAoomtest.class); enhancer.setUsecache (เท็จ); enhancer.setCallback (New MethodInterceptor () {การสกัดกั้นวัตถุสาธารณะ (วัตถุ O, วิธีการวิธี, วัตถุ [] วัตถุ, methodProxy methodProxy) พ่น throwable {return methodproxy.invokesuper (o, วัตถุ);}}); enhancer.create (); -ในรหัสข้างต้นเราใช้ CGLIB เพื่อสร้างคลาสจำนวนมากแบบไดนามิก ใน JDK6 การเรียกใช้รหัสด้านบนจะสร้าง OutofMemoryError: Permgen Space Exception:
/system/library/frameworks/javavm.framework/versions/1.6/home/bin/java -jar -xx: permsize = 10m -xx: maxpermsize = 10m เป้าหมาย/test-1.0-snapshot.jar
ผลลัพธ์ผลลัพธ์มีดังนี้:
เกิดจาก: java.lang.outofMemoryError: พื้นที่ permgen ที่ java.lang.classloader.defineclass1 (วิธีการดั้งเดิม) ที่ java.lang.classloader.defineclasscond (classloader.java:637)
Metaspace Memory Overflow
ในหน่วยความจำล้นหน่วยความจำล้นในพื้นที่เมธอดเรากล่าวว่า JDK8 ไม่มีแนวคิดของรุ่นถาวรดังนั้นตัวอย่างทั้งสองนั้นไม่ได้ผลที่คาดหวังภายใต้ JDK8 ดังนั้นใน JDK8 มีข้อผิดพลาดใด ๆ เช่นหน่วยความจำล้นในพื้นที่วิธีการหรือไม่? แน่นอนบางคน ใน JDK8 พื้นที่ Metaspace ใช้ในการจัดเก็บข้อมูลที่เกี่ยวข้องในชั้นเรียนดังนั้นเมื่อ Metaspace ไม่เพียงพอ java.lang.outofmemoryError: ข้อยกเว้น Metaspace จะถูกโยนทิ้ง
ลองใช้ตัวอย่างที่กล่าวถึงข้างต้นเป็นตัวอย่าง:
// vm args: -xx: maxmetaspacesize = 10mpublic class methodareaoomtest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ในขณะที่ (จริง) {enhancer enhancer = enhancer ใหม่ (); enhancer.setsuperclass (MethodareAoomtest.class); enhancer.setUsecache (เท็จ); enhancer.setCallback (New MethodInterceptor () {การสกัดกั้นวัตถุสาธารณะ (วัตถุ O, วิธีการวิธี, วัตถุ [] วัตถุ, methodProxy methodProxy) พ่น throwable {return methodproxy.invokesuper (o, วัตถุ);}}); enhancer.create (); -ส่วนรหัสของตัวอย่างนี้ไม่ได้มีการเปลี่ยนแปลง ความแตกต่างเพียงอย่างเดียวคือเราต้องใช้ JDK8 เพื่อเรียกใช้รหัสนี้และตั้งค่าพารามิเตอร์ -xx: MaxMetaspacesize = 10m พารามิเตอร์นี้บอก JVM ว่าขนาดสูงสุดของ metaspace คือ 10m
จากนั้นเราใช้ JDK8 เพื่อรวบรวมและเรียกใช้ตัวอย่างนี้และส่งออกข้อยกเว้นต่อไปนี้:
>>> java -jar -xx: maxmetaspacesize = 10m เป้าหมาย/test -1.0-snapshot.jarexception ในด้าย "หลัก" java.lang.outofmemoryError: metaspace ที่ net.sf.cglib.core.abstractClassGenerator.generate net.sf.cglib.proxy.enhancer.generate (enhancer.java:492) ที่ net.sf.cglib.core.abstractclassgenerator $ classloaderdata.get (AbstractClassGenerator.java:114) ที่ net.sf.cglib.core.abstractclassgenerator.create (AbstractClassGenerator.java:291) ที่ net.sf.cglib.proxy.enhancer.createhelper com.test.methodareaoomtest.main (Methodareaoomtest.java:22)
สรุป
ข้างต้นเป็นเรื่องเกี่ยวกับข้อยกเว้นของหน่วยความจำทั่วไปและตัวอย่างรหัสในบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!