מה גורם java.lang.OutOfMemoryError: לא מצליח ליצור שרשור מקורי חדש

1. הקדמה

במדריך זה נדון בסיבה ובתרופות האפשריות של java.lang.OutOfMemoryError: אין אפשרות ליצור חוט מקורי חדש שְׁגִיאָה.

2. הבנת הבעיה

2.1. סיבת הבעיה

מרבית יישומי הג'אווה מרובי הליכי טבע, המורכב ממספר רכיבים, מבצע משימות ספציפיות ומבוצע בשרשורים שונים. עם זאת, הבסיס מערכת הפעלה (OS) מטילה מכסה על המספר המרבי של שרשורים שאפליקציית Java יכולה ליצור.

ה- JVM זורק לא מצליח ליצור חוט מקורי חדש שגיאה כאשר JVM מבקש ממערכת ההפעלה הבסיסית שרשור חדש, ומערכת ההפעלה אינה מסוגלת ליצור שרשורי גרעין חדשים הידועים גם בשם מערכת ההפעלה או שרשורי מערכת. רצף האירועים הוא כדלקמן:

  1. יישום הפועל בתוך מכונת ה- Java Virtual Java (JVM) מבקש להשחיל חדש
  2. הקוד המקורי של JVM שולח בקשה למערכת ההפעלה ליצור שרשור ליבה חדש
  3. מערכת ההפעלה מנסה ליצור שרשור ליבה חדש שדורש הקצאת זיכרון
  4. מערכת ההפעלה מסרבת להקצות זיכרון מקורי מכיוון שגם
    • המבקש תהליך Java מיצה את שטח כתובות הזיכרון שלו
    • מערכת ההפעלה רוקנה את הזיכרון הווירטואלי שלה
  5. תהליך Java מחזיר את ה- java.lang.OutOfMemoryError: אין אפשרות ליצור שרשור מקורי חדש שְׁגִיאָה

2.2. מודל הקצאת חוטים

מערכת הפעלה בדרך כלל כוללת שני סוגים של שרשורים - שרשורי משתמשים (שרשורים שנוצרו על ידי יישום Java) ושרשור הליבה. שרשורי המשתמש נתמכים מעל לשרשורי הליבה ושרשורי הליבה מנוהלים על ידי מערכת ההפעלה.

ביניהם קיימות שלוש מערכות יחסים נפוצות:

  1. רבים לאחד - שרשורי משתמש רבים ממפים לשרשור גרעין יחיד
  2. אחד לאחד - מפת שרשור משתמש אחת לשרשור ליבה אחד
  3. רבים-רבים - ריבוי אשכולות משתמשים מרובים למספר קטן או שווה של שרשור הליבה

3. שכפול השגיאה

אנו יכולים ליצור מחדש את הנושא הזה על ידי יצירת שרשורים בלולאה רציפה ואז לגרום לשרשור לחכות:

בעוד (נכון) {אשכול חדש (() -> {נסה {TimeUnit.HOURS.sleep (1);} לתפוס (InterruptedException e) {e.printStackTrace ();}}). התחל (); }

מכיוון שאנו אוחזים בכל שרשור למשך שעה, תוך יצירת רציפות חדשים, נגיע במהירות למספר החוטים המרבי ממערכת ההפעלה.

4. פתרונות

אחת הדרכים לטפל בשגיאה זו היא להגדיל את תצורת הגבלת החוטים ברמת מערכת ההפעלה.

עם זאת, זה לא פיתרון אידיאלי מכיוון שה- OutOfMemoryError ככל הנראה מציין שגיאת תכנות. בואו נסתכל על כמה דרכים אחרות לפתור בעיה זו.

4.1. מינוף מסגרת שירות ההוצאה לפועל

מינוף מסגרת שירות המבצעת של ג'אווה לניהול שרשור יכול לטפל בנושא זה במידה מסוימת. מסגרת ברירת המחדל לשירות הפועלים, או תצורת הפעלה מותאמת אישית, יכולה לשלוט ביצירת פתילים.

אנחנו יכולים להשתמש ב- מוציאים לפועל # newFixedThreadPool שיטה לקביעת מספר האשכולות המרבי בו ניתן להשתמש בכל פעם:

ExecutorService executorService = Executors.newFixedThreadPool (5); Runnable runnableTask = () -> {נסה {TimeUnit.HOURS.sleep (1); } לתפוס (InterruptedException e) {// Exception Handle}}; IntStream.rangeClosed (1, 10) .forEach (i -> executorService.submit (runnableTask)); assertThat (((ThreadPoolExecutor) executorService) .getQueue (). size (), הוא (equalTo (5)));

בדוגמה שלעיל, ראשית אנו יוצרים מאגר פתילים קבוע עם חמישה שרשורים ומשימה ניתנת להפעלה שגורמת לשרשור לחכות שעה. לאחר מכן אנו מגישים עשר משימות כאלה למאגר האשכולות וקובעים כי חמש משימות ממתינות בתור שירות המבצעת.

מכיוון שמאגר האשכולות כולל חמישה נושאים, הוא יכול להתמודד עם חמש משימות לכל היותר בכל עת.

4.2. לכידת וניתוח זבל החוטים

לכידה וניתוח של זריקת החוטים שימושית להבנת מצב השרשור.

בואו נסתכל על השלכת חוט לדוגמא ונראה מה אנחנו יכולים ללמוד:

תמונת הברגה הנ"ל היא מ- Java VisualVM לדוגמא שהוצגה קודם לכן. תמונת מצב זו מדגימה בבירור את יצירת השרשור הרציפה.

ברגע שזיהינו שיש יצירה רציפה של חוטים, נוכל לתפוס את זריקת השרשור של היישום כדי לזהות את קוד המקור שיוצר את השרשור

בתצלום המצוין לעיל נוכל לזהות את הקוד האחראי ליצירת השרשור. זה מספק תובנה שימושית לנקוט באמצעים מתאימים.

5. מסקנה

במאמר זה למדנו על java.lang.OutOfMemoryError: אין אפשרות ליצור שרשור מקורי חדש שגיאה, וראינו את זה זה נגרם על ידי יצירת חוטים מוגזמת ביישום Java.

בדקנו כמה פתרונות לטיפול וניתוח השגיאה על ידי הסתכלות על שירות ExecutorService מסגרת וניתוח השלכת חוטים כשני אמצעים שימושיים להתמודדות עם נושא זה.

כמו תמיד, קוד המקור של המאמר זמין באתר GitHub.


$config[zx-auto] not found$config[zx-overlay] not found