portaldacalheta.pt
  • หลัก
  • การจัดการวิศวกรรม
  • วิทยาศาสตร์ข้อมูลและฐานข้อมูล
  • เครื่องมือและบทช่วยสอน
  • นักลงทุนและเงินทุน
เทคโนโลยี

การล่าสัตว์หน่วยความจำ Java รั่วไหล



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

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



กล่าวอีกนัยหนึ่งการรั่วไหลนั้นยากเกินไปที่จะระบุหรือระบุในรูปแบบที่เฉพาะเจาะจงเกินไปที่จะเป็นประโยชน์



ปัญหาหน่วยความจำมีสี่ประเภทที่มีอาการคล้ายกันและทับซ้อนกัน แต่สาเหตุและวิธีแก้ไขต่างกัน:



  • ประสิทธิภาพ : มักจะเกี่ยวข้องกับการสร้างและลบอ็อบเจ็กต์มากเกินไปความล่าช้าในการรวบรวมขยะเป็นเวลานานการสลับหน้าระบบปฏิบัติการมากเกินไปและอื่น ๆ

  • ข้อ จำกัด ด้านทรัพยากร : เกิดขึ้นเมื่อมีหน่วยความจำเหลือเพียงเล็กน้อยหรือหน่วยความจำของคุณกระจัดกระจายเกินกว่าที่จะจัดสรรวัตถุขนาดใหญ่ซึ่งอาจเป็นแบบเนทีฟหรือโดยทั่วไปแล้วก็คือ Java heap-related



  • การรั่วไหลของฮีป Java : การรั่วไหลของหน่วยความจำแบบคลาสสิกซึ่งวัตถุ Java ถูกสร้างขึ้นอย่างต่อเนื่องโดยไม่ปล่อยออกมา ซึ่งมักเกิดจากการอ้างอิงวัตถุแฝง

  • หน่วยความจำดั้งเดิมรั่วไหล : เชื่อมโยงกับการใช้หน่วยความจำที่เพิ่มขึ้นอย่างต่อเนื่องซึ่งอยู่นอกฮีป Java เช่นการจัดสรรที่ทำโดยรหัส JNI ไดรเวอร์หรือแม้แต่การจัดสรร JVM



ในบทช่วยสอนการจัดการหน่วยความจำนี้ฉันจะเน้นไปที่การรั่วไหลของฮีป Java และสรุปแนวทางในการตรวจจับการรั่วไหลตาม Java VisualVM รายงานและใช้อินเทอร์เฟซภาพสำหรับการวิเคราะห์ Java แอปพลิเคชันที่ใช้เทคโนโลยีในขณะที่กำลังทำงาน

แต่ก่อนที่คุณจะสามารถป้องกันและค้นหาการรั่วไหลของหน่วยความจำคุณควรเข้าใจว่าเกิดขึ้นได้อย่างไรและทำไม ( หมายเหตุ: หากคุณสามารถจัดการกับความซับซ้อนของการรั่วไหลของหน่วยความจำได้ดีคุณสามารถทำได้ ข้ามไปข้างหน้า . )



การรั่วไหลของหน่วยความจำ: ไพรเมอร์

สำหรับผู้เริ่มต้นคิดว่าการรั่วไหลของหน่วยความจำเป็นโรคและ Java's OutOfMemoryError (OOM เพื่อความกะทัดรัด) เป็นอาการ แต่เช่นเดียวกับโรคใด ๆ OOM ทั้งหมดไม่ได้หมายความถึงการรั่วไหลของหน่วยความจำ : OOM อาจเกิดขึ้นได้เนื่องจากการสร้างตัวแปรท้องถิ่นจำนวนมากหรือเหตุการณ์อื่น ๆ ดังกล่าว ในทางกลับกัน, การรั่วไหลของหน่วยความจำทั้งหมดไม่จำเป็นต้องแสดงตัวเองว่าเป็น OOM โดยเฉพาะอย่างยิ่งในกรณีของแอปพลิเคชันเดสก์ท็อปหรือแอปพลิเคชันไคลเอนต์ (ซึ่งจะไม่ทำงานเป็นเวลานานโดยไม่รีสตาร์ท)

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

ทำไมการรั่วไหลเหล่านี้จึงแย่มาก? เหนือสิ่งอื่นใดบล็อกหน่วยความจำที่รั่วไหลระหว่างการทำงานของโปรแกรมมักจะลดระดับลง ประสิทธิภาพของระบบ เมื่อเวลาผ่านไปเนื่องจากบล็อกหน่วยความจำที่จัดสรร แต่ไม่ได้ใช้จะต้องถูกสลับออกเมื่อระบบไม่มีหน่วยความจำกายภาพที่ว่างเหลืออยู่ ในที่สุดโปรแกรมอาจใช้พื้นที่ที่อยู่เสมือนที่มีอยู่จนหมดซึ่งนำไปสู่ ​​OOM



การถอดรหัส OutOfMemoryError

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

ขั้นตอนแรกในการวินิจฉัย OOM ของคุณคือการกำหนดความหมายของข้อผิดพลาด ฟังดูชัดเจน แต่คำตอบไม่ชัดเจนเสมอไป ตัวอย่าง: OOM ปรากฏขึ้นเนื่องจากฮีป Java เต็มหรือเนื่องจากฮีปเนทีฟเต็ม? เพื่อช่วยคุณตอบคำถามนี้เรามาวิเคราะห์ข้อความแสดงข้อผิดพลาดที่เป็นไปได้บางส่วน:



  • java.lang.OutOfMemoryError: Java heap space

  • java.lang.OutOfMemoryError: PermGen space

  • java.lang.OutOfMemoryError: Requested array size exceeds VM limit

  • java.lang.OutOfMemoryError: request bytes for . Out of swap space?

  • java.lang.OutOfMemoryError: (Native method)

“ Java heap space”

ข้อความแสดงข้อผิดพลาดนี้ไม่ได้หมายความถึงหน่วยความจำรั่วเสมอไป ในความเป็นจริงปัญหาอาจเป็นเรื่องง่ายเหมือนปัญหาการกำหนดค่า

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

ในกรณีอื่น ๆ และโดยเฉพาะอย่างยิ่งสำหรับแอปพลิเคชันที่มีอายุการใช้งานยาวนานข้อความอาจบ่งชี้ว่าเราไม่ได้ตั้งใจ ถือการอ้างอิงถึงวัตถุ ป้องกันไม่ให้คนเก็บขยะทำความสะอาด นี่คือภาษา Java เทียบเท่ากับการรั่วไหลของหน่วยความจำ . ( หมายเหตุ: API ที่เรียกโดยแอปพลิเคชันอาจถือการอ้างอิงอ็อบเจ็กต์โดยไม่ได้ตั้งใจ )

แหล่งที่มาที่เป็นไปได้อีกประการหนึ่งของ OOMs 'Java heap space' เหล่านี้เกิดขึ้นจากการใช้ Finalizers . ถ้าชั้นเรียนมี finalize วิธีการจากนั้นวัตถุประเภทนั้นจะไม่มีการเรียกคืนพื้นที่ในเวลารวบรวมขยะ หลังจากการรวบรวมขยะวัตถุจะถูกจัดคิวสำหรับการสรุปซึ่งจะเกิดขึ้นในภายหลัง ในการนำไปใช้งาน Sun ผู้สรุปจะดำเนินการโดย a เธรด daemon . หากเธรด Finalizer ไม่สามารถทำตามคิวการปิดท้ายได้ฮีป Java สามารถเติมเต็มและ OOM อาจถูกโยนทิ้ง

“ พื้นที่ PermGen”

ข้อความแสดงข้อผิดพลาดนี้ระบุว่าไฟล์ รุ่นถาวร เต็ม. การสร้างแบบถาวรคือพื้นที่ของฮีปที่เก็บคลาสและอ็อบเจ็กต์เมธอด หากแอปพลิเคชันโหลดคลาสจำนวนมากขนาดของรุ่นถาวรอาจต้องเพิ่มขึ้นโดยใช้ -XX:MaxPermSize ตัวเลือก

ฝึกงาน java.lang.String วัตถุจะถูกเก็บไว้ในรุ่นถาวรด้วย java.lang.String คลาสรักษาพูลของสตริง เมื่อเรียกใช้เมธอด intern เมธอดจะตรวจสอบพูลเพื่อดูว่ามีสตริงที่เท่ากันหรือไม่ หากเป็นเช่นนั้นจะส่งคืนโดยวิธีการฝึกงาน หากไม่เป็นเช่นนั้นสตริงจะถูกเพิ่มลงในพูล ในแง่ที่แม่นยำยิ่งขึ้นคือ java.lang.String.intern วิธีการคืนค่าสตริง การแสดงตามบัญญัติ ; ผลลัพธ์คือการอ้างอิงไปยังอินสแตนซ์คลาสเดียวกันที่จะถูกส่งกลับหากสตริงนั้นปรากฏเป็นลิเทอรัล หากแอปพลิเคชันใช้สตริงจำนวนมากคุณอาจต้องเพิ่มขนาดของการสร้างแบบถาวร

หมายเหตุ: คุณสามารถใช้ jmap -permgen คำสั่งเพื่อพิมพ์สถิติที่เกี่ยวข้องกับการสร้างแบบถาวรรวมถึงข้อมูลเกี่ยวกับอินสแตนซ์ String ภายใน

'ขนาดอาร์เรย์ที่ขอเกินขีด จำกัด VM'

ข้อผิดพลาดนี้บ่งชี้ว่าแอปพลิเคชัน (หรือ API ที่ใช้โดยแอปพลิเคชันนั้น) พยายามจัดสรรอาร์เรย์ที่มีขนาดใหญ่กว่าขนาดฮีป ตัวอย่างเช่นหากแอปพลิเคชันพยายามจัดสรรอาร์เรย์ 512MB แต่ขนาดฮีปสูงสุดคือ 256MB OOM จะแสดงข้อความแสดงข้อผิดพลาดนี้ ในกรณีส่วนใหญ่ปัญหาอาจเป็นปัญหาการกำหนดค่าหรือข้อบกพร่องที่เกิดขึ้นเมื่อแอปพลิเคชันพยายามจัดสรรอาร์เรย์จำนวนมาก

“ ขอไบต์สำหรับ. ไม่มีพื้นที่แลกเปลี่ยนหรือไม่”

ข้อความนี้ดูเหมือนจะเป็น OOM อย่างไรก็ตาม HotSpot VM จะแสดงข้อยกเว้นที่ชัดเจนนี้เมื่อการจัดสรรจากฮีปเนทีฟล้มเหลวและฮีปเนทีฟอาจใกล้จะหมดลง ข้อความที่รวมอยู่ในข้อความคือขนาด (เป็นไบต์) ของคำขอที่ล้มเหลวและสาเหตุของการร้องขอหน่วยความจำ ในกรณีส่วนใหญ่ชื่อของโมดูลต้นทางที่รายงานการจัดสรรล้มเหลว

หาก OOM ประเภทนี้ถูกส่งออกไปคุณอาจต้องใช้ยูทิลิตี้การแก้ไขปัญหาบนระบบปฏิบัติการของคุณเพื่อวินิจฉัยปัญหาเพิ่มเติม ในบางกรณีปัญหาอาจไม่เกี่ยวข้องกับแอปพลิเคชันด้วยซ้ำ ตัวอย่างเช่นคุณอาจเห็นข้อผิดพลาดนี้หาก:

  • ระบบปฏิบัติการได้รับการกำหนดค่าโดยมีพื้นที่สวอปไม่เพียงพอ

  • กระบวนการอื่นในระบบกำลังใช้ทรัพยากรหน่วยความจำที่มีอยู่ทั้งหมด

นอกจากนี้ยังเป็นไปได้ว่าแอปพลิเคชันล้มเหลวเนื่องจากการรั่วไหลในระบบ (ตัวอย่างเช่นหากบิตของแอปพลิเคชันหรือรหัสไลบรารีบางส่วนจัดสรรหน่วยความจำอย่างต่อเนื่อง แต่ไม่สามารถปล่อยลงในระบบปฏิบัติการได้)

(วิธีดั้งเดิม)

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

หาก OOM ประเภทนี้ถูกส่งออกไปคุณอาจต้องใช้ยูทิลิตี้บนระบบปฏิบัติการเพื่อวินิจฉัยปัญหาเพิ่มเติม

แอปพลิเคชันขัดข้องโดยไม่มี OOM

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

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

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

การวินิจฉัยการรั่วไหล

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

กลยุทธ์ของเราในการค้นหาการรั่วไหลของหน่วยความจำจะค่อนข้างตรงไปตรงมา:

  1. ระบุอาการ

  2. เปิดใช้งานการรวบรวมขยะแบบละเอียด

  3. เปิดใช้งานการสร้างโปรไฟล์

  4. วิเคราะห์การติดตาม

1. ระบุอาการ

ตามที่กล่าวไว้ในหลาย ๆ กรณีกระบวนการ Java จะทำให้เกิดข้อยกเว้นรันไทม์ OOM ซึ่งเป็นตัวบ่งชี้ที่ชัดเจนว่าทรัพยากรหน่วยความจำของคุณหมดลงแล้ว ในกรณีนี้คุณต้องแยกความแตกต่างระหว่างความจำเสื่อมปกติและการรั่วไหล วิเคราะห์ข้อความของ OOM และพยายามค้นหาผู้กระทำผิดตามการอภิปรายที่ให้ไว้ข้างต้น

บ่อยครั้งหากแอ็พพลิเคชัน Java ร้องขอพื้นที่เก็บข้อมูลมากกว่าที่ฮีปรันไทม์เสนออาจเป็นเพราะการออกแบบที่ไม่ดี ตัวอย่างเช่นหากแอปพลิเคชันสร้างสำเนารูปภาพหลายชุดหรือโหลดไฟล์ลงในอาร์เรย์แอปพลิเคชันจะไม่มีพื้นที่เก็บข้อมูลเมื่อรูปภาพหรือไฟล์มีขนาดใหญ่มาก นี่เป็นความเหนื่อยล้าของทรัพยากรตามปกติ แอปพลิเคชันทำงานตามที่ออกแบบไว้ (แม้ว่าการออกแบบนี้จะมีหัวกระดูกอย่างชัดเจน)

แต่หากแอปพลิเคชันเพิ่มการใช้หน่วยความจำไปเรื่อย ๆ ในขณะที่ประมวลผลข้อมูลประเภทเดียวกันคุณอาจมีหน่วยความจำรั่ว

2. เปิดใช้งาน Verbose Garbage Collection

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

โดยเฉพาะไฟล์ -verbosegc อาร์กิวเมนต์อนุญาตให้คุณสร้างการติดตามทุกครั้งที่กระบวนการรวบรวมขยะ (GC) เริ่มต้นขึ้น นั่นคือในขณะที่หน่วยความจำกำลังถูกเก็บรวบรวมเป็นขยะรายงานสรุปจะถูกพิมพ์เป็นข้อผิดพลาดมาตรฐานทำให้คุณทราบว่าหน่วยความจำของคุณได้รับการจัดการอย่างไร

นี่คือผลลัพธ์ทั่วไปบางส่วนที่สร้างขึ้นด้วย –verbosegc ตัวเลือก:

เอาต์พุตการรวบรวมขยะแบบละเอียด

แต่ละบล็อก (หรือ stanza) ในไฟล์การติดตาม GC นี้มีหมายเลขตามลำดับที่เพิ่มขึ้น เพื่อให้เข้าใจถึงร่องรอยนี้คุณควรดูที่บทวิเคราะห์ Allocation Failure ที่ต่อเนื่องกันและมองหาหน่วยความจำที่ว่าง (ไบต์และเปอร์เซ็นต์) ลดลงเมื่อเวลาผ่านไปในขณะที่หน่วยความจำทั้งหมด (ที่นี่ 19725304) กำลังเพิ่มขึ้น นี่เป็นสัญญาณทั่วไปของความจำพร่อง

3. เปิดใช้งานการทำโปรไฟล์

JVM ที่แตกต่างกันเสนอวิธีต่างๆในการสร้างไฟล์การติดตามเพื่อสะท้อนกิจกรรมฮีปซึ่งโดยทั่วไปจะมีข้อมูลโดยละเอียดเกี่ยวกับประเภทและขนาดของวัตถุ นี้เรียกว่า การทำโปรไฟล์ฮีป .

4. วิเคราะห์การติดตาม

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

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

Garbage Collection ทำงานอย่างไรใน JVM?

ก่อนที่เราจะเริ่มวิเคราะห์แอปพลิเคชันที่มีปัญหาหน่วยความจำรั่วก่อนอื่นเรามาดูวิธีการทำงานของการรวบรวมขยะใน JVM

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

Java ใช้สิ่งที่เรียกว่า รุ่น คนเก็บขยะตามสมมติฐานของเจเนอเรชั่นอลซึ่งระบุว่า วัตถุส่วนใหญ่ที่สร้างขึ้นจะถูกทิ้งอย่างรวดเร็ว และ วัตถุที่ไม่ได้รับการรวบรวมอย่างรวดเร็วน่าจะอยู่ในช่วงเวลาหนึ่ง .

จากสมมติฐานนี้ พาร์ติชัน Java ออบเจ็กต์เป็นหลายชั่วอายุคน . นี่คือการตีความภาพ:

Java แบ่งออกเป็นหลายรุ่น

  • คนรุ่นใหม่ - นี่คือจุดเริ่มต้นของวัตถุ มีสองรุ่นย่อย:

    • เอเดนสเปซ - วัตถุเริ่มต้นที่นี่ วัตถุส่วนใหญ่ถูกสร้างและทำลายใน Eden Space ที่นี่ GC ทำ GC เล็กน้อย ซึ่งเป็นการรวบรวมขยะที่เหมาะสมที่สุด เมื่อดำเนินการ Minor GC การอ้างอิงถึงอ็อบเจ็กต์ที่ยังจำเป็นจะถูกโอนย้ายไปยังช่องว่างผู้รอดชีวิต (S0 หรือ S1)

    • Survivor Space (S0 และ S1) - วัตถุที่อยู่รอดในสวนอีเดนจบลงที่นี่ มีสองสิ่งนี้และมีเพียงหนึ่งเดียวที่ถูกใช้งานในช่วงเวลาใดเวลาหนึ่ง (เว้นแต่เราจะมีการรั่วไหลของหน่วยความจำที่ร้ายแรง) หนึ่งถูกกำหนดให้เป็น ว่างเปล่า และอื่น ๆ เป็น มีชีวิต สลับกับทุกรอบ GC

  • รุ่นอายุยืน - หรือที่เรียกว่าคนรุ่นเก่า (พื้นที่เก่าในรูปที่ 2) พื้นที่นี้เก็บวัตถุรุ่นเก่าที่มีอายุการใช้งานยาวนานขึ้น (ย้ายจากช่องว่างของผู้รอดชีวิตหากมีชีวิตอยู่นานพอ) เมื่อเติมช่องว่างนี้ GC จะทำไฟล์ GC เต็มรูปแบบ ซึ่งมีค่าใช้จ่ายมากกว่าในแง่ของประสิทธิภาพ หากช่องว่างนี้เติบโตขึ้นโดยไม่มีขอบเขต JVM จะโยน OutOfMemoryError - Java heap space

  • รุ่นถาวร - รุ่นที่สามที่เกี่ยวข้องอย่างใกล้ชิดกับรุ่นที่ครอบครองรุ่นถาวรมีความพิเศษเนื่องจากเก็บข้อมูลที่เครื่องเสมือนต้องการเพื่ออธิบายวัตถุที่ไม่มีความเท่าเทียมกันในระดับภาษา Java ตัวอย่างเช่นอ็อบเจ็กต์ที่อธิบายคลาสและเมธอดจะถูกเก็บไว้ในการสร้างแบบถาวร

Java ฉลาดพอที่จะใช้วิธีการเก็บขยะที่แตกต่างกันไปในแต่ละรุ่น คนรุ่นใหม่ได้รับการจัดการโดยใช้ไฟล์ การติดตามการคัดลอกตัวรวบรวม เรียกว่า นักสะสมใหม่แบบขนาน . นักสะสมคนนี้หยุดโลก แต่เนื่องจากคนรุ่นใหม่มักตัวเล็กการหยุดชั่วคราวจึงสั้น

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับรุ่น JVM และวิธีการทำงานโดยละเอียดโปรดไปที่ การจัดการหน่วยความจำใน Java HotSpot Virtual Machine เอกสารประกอบ.

การตรวจจับการรั่วไหลของหน่วยความจำ

หากต้องการค้นหาการรั่วไหลของหน่วยความจำและกำจัดออกคุณต้องมีเครื่องมือหน่วยความจำรั่วที่เหมาะสม ได้เวลาตรวจจับและกำจัดการรั่วไหลโดยใช้ไฟล์ Java VisualVM .

สร้างโปรไฟล์ Heap จากระยะไกลด้วย Java VisualVM

VisualVM เป็นเครื่องมือที่มีอินเทอร์เฟซภาพสำหรับการดูข้อมูลโดยละเอียดเกี่ยวกับแอปพลิเคชันที่ใช้เทคโนโลยี Java ในขณะที่กำลังทำงาน

ด้วย VisualVM คุณสามารถดูข้อมูลที่เกี่ยวข้องกับแอปพลิเคชันภายในเครื่องและข้อมูลที่ทำงานบนโฮสต์ระยะไกล คุณยังสามารถเก็บข้อมูลเกี่ยวกับอินสแตนซ์ซอฟต์แวร์ JVM และบันทึกข้อมูลลงในระบบภายในของคุณ

เพื่อให้ได้รับประโยชน์จากคุณลักษณะทั้งหมดของ Java VisualVM คุณควรเรียกใช้ Java Platform, Standard Edition (Java SE) เวอร์ชัน 6 ขึ้นไป

ที่เกี่ยวข้อง: ทำไมคุณต้องอัพเกรดเป็น Java 8 อยู่แล้ว

การเปิดใช้งานการเชื่อมต่อระยะไกลสำหรับ JVM

ในสภาพแวดล้อมการใช้งานจริงมักจะยากที่จะเข้าถึงเครื่องจริงที่จะใช้โค้ดของเรา โชคดีที่เราสามารถกำหนดโปรไฟล์แอปพลิเคชัน Java ของเราได้จากระยะไกล

ขั้นแรกเราต้องให้สิทธิ์ตัวเองในการเข้าถึง JVM บนเครื่องเป้าหมาย โดยสร้างไฟล์ชื่อ jstatd.all.policy โดยมีเนื้อหาดังต่อไปนี้:

grant codebase 'file:${java.home}/../lib/tools.jar' { permission java.security.AllPermission; };

เมื่อสร้างไฟล์แล้วเราจำเป็นต้องเปิดใช้งานการเชื่อมต่อระยะไกลไปยัง VM เป้าหมายโดยใช้ไฟล์ jstatd - เครื่องเสมือน jstat Daemon เครื่องมือดังต่อไปนี้:

jstatd -p -J-Djava.security.policy=

ตัวอย่างเช่น:

jstatd -p 1234 -J-Djava.security.policy=D:jstatd.all.policy

กับ jstatd เริ่มต้นใน VM เป้าหมายเราสามารถเชื่อมต่อกับเครื่องเป้าหมายและกำหนดโปรไฟล์แอปพลิเคชันจากระยะไกลที่มีปัญหาหน่วยความจำรั่ว

การเชื่อมต่อกับโฮสต์ระยะไกล

ในเครื่องไคลเอนต์เปิดพรอมต์แล้วพิมพ์ jvisualvm เพื่อเปิดเครื่องมือ VisualVM

ต่อไปเราต้องเพิ่มโฮสต์ระยะไกลใน VisualVM เนื่องจาก JVM เป้าหมายถูกเปิดใช้งานเพื่ออนุญาตการเชื่อมต่อระยะไกลจากเครื่องอื่นที่มี J2SE 6 หรือสูงกว่าเราจึงเริ่มเครื่องมือ Java VisualVM และเชื่อมต่อกับโฮสต์ระยะไกล หากการเชื่อมต่อกับโฮสต์ระยะไกลประสบความสำเร็จเราจะเห็นแอปพลิเคชัน Java ที่ทำงานใน JVM เป้าหมายดังที่เห็นที่นี่:

ทำงานใน jvm เป้าหมาย

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

ตอนนี้เราได้ติดตั้งเครื่องวิเคราะห์หน่วยความจำเรียบร้อยแล้วเรามาตรวจสอบแอปพลิเคชันที่มีปัญหาหน่วยความจำรั่วซึ่งเราจะเรียกว่า MemLeak .

MemLeak

แน่นอนว่ามีหลายวิธีในการสร้างการรั่วไหลของหน่วยความจำใน Java เพื่อความง่ายเราจะกำหนดคลาสให้เป็นคีย์ใน a HashMap แต่เราจะไม่กำหนด เท่ากับ () และ hashcode () วิธีการ

HashMap คือไฟล์ ตารางแฮช การนำไปใช้งานสำหรับอินเทอร์เฟซแผนที่และด้วยเหตุนี้จึงกำหนดแนวคิดพื้นฐานของคีย์และค่า: แต่ละค่าเกี่ยวข้องกับคีย์ที่ไม่ซ้ำกันดังนั้นหากคีย์สำหรับคู่คีย์ - ค่าที่กำหนดมีอยู่แล้วใน HashMap ค่าปัจจุบันจะเป็น แทนที่

จำเป็นต้องมีคลาสสำคัญของเราต้องนำ equals() ไปใช้อย่างถูกต้อง และ hashcode() วิธีการ หากไม่มีพวกเขาก็ไม่มีการรับประกันว่าจะมีการสร้างคีย์ที่ดี

โดยไม่กำหนด equals() และ hashcode() วิธีการเราเพิ่มคีย์เดียวกันลงใน HashMap ซ้ำแล้วซ้ำอีกและแทนที่จะแทนที่คีย์ตามที่ควรจะเป็น HashMap เติบโตขึ้นอย่างต่อเนื่องล้มเหลวในการระบุคีย์ที่เหมือนกันเหล่านี้และโยน OutOfMemoryError

นี่คือคลาส MemLeak:

package com.post.memory.leak; import java.util.Map; public class MemLeak { public final String key; public MemLeak(String key) { this.key =key; } public static void main(String args[]) { try { Map map = System.getProperties(); for(;;) { map.put(new MemLeak('key'), 'value'); } } catch(Exception e) { e.printStackTrace(); } } }

หมายเหตุ: หน่วยความจำรั่วคือ ไม่ เนื่องจากการวนซ้ำที่ไม่มีที่สิ้นสุดในบรรทัดที่ 14: การวนซ้ำแบบไม่มีที่สิ้นสุดสามารถนำไปสู่การหมดทรัพยากร แต่ไม่ใช่การรั่วไหลของหน่วยความจำ หากเรานำมาใช้อย่างถูกต้อง equals() และ hashcode() วิธีการโค้ดจะทำงานได้ดีแม้จะมีการวนซ้ำแบบไม่มีที่สิ้นสุดเนื่องจากเราจะมีเพียงองค์ประกอบเดียวใน HashMap

(สำหรับผู้ที่สนใจ ที่นี่ เป็นทางเลือกอื่นในการก่อให้เกิดการรั่วไหล (โดยเจตนา))

ใช้ Java VisualVM

ด้วย Java VisualVM เราสามารถตรวจสอบหน่วยความจำ Java Heap และระบุว่าพฤติกรรมของมันบ่งบอกถึงการรั่วไหลของหน่วยความจำหรือไม่

นี่คือการนำเสนอแบบกราฟิกของตัววิเคราะห์ Java Heap ของ MemLeak หลังจากเริ่มต้นใช้งาน (นึกถึงการอภิปรายของเราเกี่ยวกับ ชั่วอายุคน ):

ตรวจสอบการรั่วไหลของหน่วยความจำโดยใช้ java visualvm

หลังจากผ่านไปเพียง 30 วินาที Old Generation ก็ใกล้จะเต็มแสดงให้เห็นว่าแม้จะมี GC เต็มรูปแบบ แต่ Old Generation ก็เติบโตขึ้นเรื่อย ๆ ซึ่งเป็นสัญญาณที่ชัดเจนของการรั่วไหลของหน่วยความจำ

วิธีหนึ่งในการตรวจหาสาเหตุของการรั่วไหลนี้แสดงในภาพต่อไปนี้ ( คลิกเพื่อซูม ) สร้างขึ้นโดยใช้ Java VisualVM พร้อมกับไฟล์ heapdump . ที่นี่เราเห็นว่า 50% ของวัตถุ Hashtable $ Entry อยู่ในฮีป ในขณะที่บรรทัดที่สองชี้เราไปที่ไฟล์ MemLeak ชั้นเรียน. ดังนั้นหน่วยความจำรั่วจึงเกิดจากไฟล์ ตารางแฮช ใช้ภายในไฟล์ MemLeak ชั้นเรียน.

หน่วยความจำตารางแฮชรั่ว

สุดท้ายให้สังเกต Java Heap หลังจาก OutOfMemoryError ของเรา ซึ่งใน เยาวชนและคนรุ่นเก่าเต็มไปหมด .

outofmemoryerror

สรุป

การรั่วไหลของหน่วยความจำเป็นหนึ่งในแอปพลิเคชัน Java ที่ยากที่สุด ปัญหาในการแก้ไข เนื่องจากอาการมีความหลากหลายและเกิดซ้ำได้ยาก ที่นี่เราได้สรุปวิธีการทีละขั้นตอนในการค้นหาการรั่วไหลของหน่วยความจำและระบุแหล่งที่มา แต่เหนือสิ่งอื่นใดอ่านข้อความแสดงข้อผิดพลาดของคุณอย่างละเอียดและใส่ใจกับสแต็กเทรซของคุณการรั่วไหลทั้งหมดไม่ง่ายอย่างที่ปรากฏ

ภาคผนวก

นอกจาก Java VisualVM แล้วยังมีเครื่องมืออื่น ๆ อีกมากมายที่สามารถตรวจจับการรั่วไหลของหน่วยความจำได้ เครื่องตรวจจับการรั่วไหลจำนวนมากทำงานในระดับไลบรารีโดยดักฟังการโทรไปยังรูทีนการจัดการหน่วยความจำ ตัวอย่างเช่น HPROF เป็นเครื่องมือบรรทัดคำสั่งง่ายๆที่มาพร้อมกับ Java 2 Platform Standard Edition (J2SE) สำหรับการทำโปรไฟล์ฮีปและ CPU ผลลัพธ์ของ HPROF สามารถวิเคราะห์โดยตรงหรือใช้เป็นอินพุตสำหรับเครื่องมืออื่น ๆ เช่น JHAT เมื่อเราทำงานกับแอปพลิเคชัน Java 2 Enterprise Edition (J2EE) มีโซลูชันตัววิเคราะห์ฮีปดัมพ์จำนวนมากที่เป็นมิตรกว่าเช่น IBM Heapdumps สำหรับแอ็พพลิเคชันเซิร์ฟเวอร์ Websphere .

ทำความเข้าใจพื้นฐาน

หน่วยความจำรั่วคืออะไร?

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

aws โซลูชันสถาปนิก สอบสมทบ

คุณจะแก้ไขหน่วยความจำรั่วได้อย่างไร?

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

คุณพบหน่วยความจำรั่วได้อย่างไร?

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

ขนาดฮีปคืออะไร?

ขนาดฮีปกำหนดจำนวนหน่วยความจำที่พร้อมใช้งานสำหรับ JVM สำหรับการจัดสรร เมื่อใดก็ตามที่คุณสร้างออบเจ็กต์ใหม่วัตถุนั้นจะถูกเก็บไว้ในฮีปอย่างต่อเนื่อง

การรวบรวมขยะทำงานอย่างไรใน Java

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

วิธีแก้ไขการรั่วไหลของหน่วยความจำใน Java

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

React, Redux และ Immutable.js: ส่วนผสมสำหรับเว็บแอปพลิเคชันที่มีประสิทธิภาพ

เทคโนโลยี

React, Redux และ Immutable.js: ส่วนผสมสำหรับเว็บแอปพลิเคชันที่มีประสิทธิภาพ
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ

แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ

การทำกำไรและประสิทธิภาพ

โพสต์ยอดนิยม
วิธีการรับสมัครผู้เข้าร่วมวิจัย UX
วิธีการรับสมัครผู้เข้าร่วมวิจัย UX
การลงทุนใน Cryptocurrencies: The Ultimate Guide
การลงทุนใน Cryptocurrencies: The Ultimate Guide
การออกแบบเว็บไซต์ CMS: คู่มือการใช้งานเนื้อหาแบบไดนามิก
การออกแบบเว็บไซต์ CMS: คู่มือการใช้งานเนื้อหาแบบไดนามิก
บทช่วยสอนเกี่ยวกับส่วนขยายแอป iOS 8
บทช่วยสอนเกี่ยวกับส่วนขยายแอป iOS 8
การดำดิ่งสู่ React Native (บทช่วยสอนสำหรับผู้เริ่มต้น)
การดำดิ่งสู่ React Native (บทช่วยสอนสำหรับผู้เริ่มต้น)
 
Init.js: คำแนะนำเกี่ยวกับเหตุผลและวิธีการของชุดเทคโนโลยี JavaScript
Init.js: คำแนะนำเกี่ยวกับเหตุผลและวิธีการของชุดเทคโนโลยี JavaScript
สาเหตุและผลกระทบ - การสำรวจจิตวิทยาสี
สาเหตุและผลกระทบ - การสำรวจจิตวิทยาสี
คุณต้องการฮีโร่: ผู้จัดการโครงการ
คุณต้องการฮีโร่: ผู้จัดการโครงการ
แนวทางปฏิบัติที่ดีที่สุดในการออกแบบ UI เพื่อการสแกนที่ดีขึ้น
แนวทางปฏิบัติที่ดีที่สุดในการออกแบบ UI เพื่อการสแกนที่ดีขึ้น
13 Podcasts นักออกแบบทุกคนควรฟัง
13 Podcasts นักออกแบบทุกคนควรฟัง
โพสต์ยอดนิยม
  • โหนดแพลตฟอร์มคลาวด์ของ Google js
  • หน้าที่ของcfoคืออะไร?
  • การทราบความยืดหยุ่นของราคาสินค้าช่วยให้นักเศรษฐศาสตร์สามารถ
  • กวดวิชา c ++ ขั้นสูง
  • การใช้ node.js . คืออะไร
  • หุ่นยนต์ใช้ภาษาการเขียนโปรแกรมอะไร
หมวดหมู่
  • การจัดการวิศวกรรม
  • วิทยาศาสตร์ข้อมูลและฐานข้อมูล
  • เครื่องมือและบทช่วยสอน
  • นักลงทุนและเงินทุน
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt