كيفية التعامل مع "java.lang.OutOfMemoryError:خطأ في مساحة كومة جافا؟

StackOverflow https://stackoverflow.com/questions/37335

سؤال

أنا أكتب من جانب العميل يتأرجح تطبيق (مصمم الخطوط الرسومية) على جافا 5.في الآونة الأخيرة، أنا أواجه java.lang.OutOfMemoryError: Java heap space خطأ لأنني لست متحفظًا بشأن استخدام الذاكرة.يمكن للمستخدم فتح عدد غير محدود من الملفات، ويحتفظ البرنامج بالكائنات المفتوحة في الذاكرة.وبعد بحث سريع وجدت بيئة العمل في 5.0 Java Virtual Machine وآخرون يقولون على جهاز يعمل بنظام Windows أن JVM الافتراضي هو الحد الأقصى لحجم الكومة 64MB.

في ظل هذا الوضع، كيف يجب أن أتعامل مع هذا القيد؟

يمكنني زيادة الحد الأقصى لحجم الكومة استخدام سطر الأوامر خيار جافا، ولكن ذلك قد يتطلب معرفة ذاكرة الوصول العشوائي المتوفرة وكتابة بعض برامج التشغيل أو البرامج النصية.علاوة على ذلك، زيادة على البعض محدود الحد الأقصى لا أخيرًا تخلص من هذه القضية.

يمكنني إعادة كتابة بعض التعليمات البرمجية الخاصة بي لاستمرار الكائنات في نظام الملفات بشكل متكرر (استخدام قاعدة البيانات هو نفس الشيء) لتحرير الذاكرة.يمكن أن ينجح الأمر، لكن من المحتمل أن يتطلب الكثير من العمل أيضًا.

إذا كان بإمكانك توجيهي إلى تفاصيل الأفكار المذكورة أعلاه أو بعض البدائل مثل الذاكرة الافتراضية التلقائية، وتوسيع حجم الكومة بشكل حيوي, ، ذلك سيكون رائعا.

هل كانت مفيدة؟

المحلول

في النهاية، لديك دائمًا حد أقصى محدود من الكومة لاستخدامها بغض النظر عن النظام الأساسي الذي تعمل عليه.في نظام التشغيل Windows 32 بت، هذا موجود 2GB (ليس كومة على وجه التحديد ولكن إجمالي مقدار الذاكرة لكل عملية).يحدث فقط أن Java اختارت جعل الإعداد الافتراضي أصغر (من المفترض حتى لا يتمكن المبرمج من إنشاء برامج ذات تخصيص جامح للذاكرة دون الوقوع في هذه المشكلة والاضطرار إلى فحص ما يفعلونه بالضبط).

لذلك، نظرًا لوجود العديد من الطرق التي يمكنك اتباعها لتحديد مقدار الذاكرة التي تحتاجها أو لتقليل مقدار الذاكرة التي تستخدمها.أحد الأخطاء الشائعة في اللغات المجمعة المهملة مثل Java أو C# هو الاحتفاظ بالمراجع إلى الكائنات التي تريدها ليس اطول تستخدم أو تخصص العديد من الكائنات عندما تستطيع ذلك إعادة استخدام لهم بدلا من ذلك.طالما أن الكائنات لديها مرجع إليها، فسوف تستمر في استخدام مساحة الكومة حيث لن يقوم جامع البيانات المهملة بحذفها.

في هذه الحالة، يمكنك استخدام ملف تعريف ذاكرة Java لتحديد الأساليب الموجودة في برنامجك والتي تقوم بتخصيص عدد كبير من الكائنات ثم تحديد ما إذا كانت هناك طريقة للتأكد من أنه لم يعد يتم الرجوع إليها، أو عدم تخصيصها في المقام الأول.أحد الخيارات التي استخدمتها في الماضي هو "JMP" http://www.khelekore.org/jmp/.

إذا قررت أنك تقوم بتخصيص هذه الكائنات لسبب ما وتحتاج إلى الاحتفاظ بالمراجع (اعتمادًا على ما تفعله، فقد يكون هذا هو الحال)، فستحتاج فقط إلى زيادة الحد الأقصى لحجم الكومة عند بدء تشغيل البرنامج.ومع ذلك، بمجرد قيامك بتنميط الذاكرة وفهم كيفية تخصيص الكائنات الخاصة بك، يجب أن يكون لديك فكرة أفضل عن مقدار الذاكرة التي تحتاجها.

بشكل عام، إذا لم تتمكن من ضمان تشغيل برنامجك بكمية محدودة من الذاكرة (ربما اعتمادًا على حجم الإدخال)، فسوف تواجه دائمًا هذه المشكلة.فقط بعد استنفاد كل هذا سوف تحتاج إلى النظر في تخزين الكائنات مؤقتًا على القرص وما إلى ذلك.في هذه المرحلة، يجب أن يكون لديك سبب وجيه جدًا لقول "أحتاج إلى Xgb من الذاكرة" لشيء ما ولا يمكنك التغلب عليه من خلال تحسين الخوارزميات أو أنماط تخصيص الذاكرة.بشكل عام، سيكون هذا هو الحال عادةً فقط بالنسبة للخوارزميات التي تعمل على مجموعات بيانات كبيرة (مثل قاعدة بيانات أو بعض برامج التحليل العلمي) ومن ثم تصبح تقنيات مثل التخزين المؤقت وإدخال/إخراج الذاكرة المعينة مفيدة.

نصائح أخرى

قم بتشغيل Java باستخدام خيار سطر الأوامر -Xmx, ، والذي يحدد أقصى حجم الكومة.

انظر هنا للحصول على التفاصيل.

يمكنك تحديد لكل عرض مقدار مساحة الكومة التي يريدها مشروعك

التالي هو ل الكسوف هيليوس / جونو / كيبلر:

انقر بزر الماوس الأيمن على

 Run As - Run Configuration - Arguments - Vm Arguments, 

ثم أضف هذا

-Xmx2048m

زيادة حجم الكومة ليس "إصلاحًا" بل هو "جص" مؤقت 100٪.سوف يتعطل مرة أخرى في مكان آخر.لتجنب هذه المشكلات، قم بكتابة تعليمات برمجية عالية الأداء.

  1. استخدم المتغيرات المحلية حيثما أمكن ذلك.
  2. تأكد من تحديد الكائن الصحيح (على سبيل المثال:الاختيار بين String وStringBuffer وStringBuilder)
  3. استخدم نظام كود جيد لبرنامجك (على سبيل المثال:استخدام المتغيرات الثابتة مقابل المتغيرات غير الثابتة)
  4. أشياء أخرى يمكن أن تعمل على التعليمات البرمجية الخاصة بك.
  5. حاول التحرك باستخدام خيوط متعددة

تحذير كبير ---- في مكتبي، وجدنا أنه (في بعض أجهزة Windows) لم نتمكن من تخصيص أكثر من 512 مليونًا لكومة Java.وتبين أن هذا يرجع إلى تثبيت منتج مكافحة الفيروسات Kaspersky على بعض هذه الأجهزة.بعد إلغاء تثبيت منتج AV هذا، وجدنا أنه يمكننا تخصيص 1.6 جيجابايت على الأقل، أي: -Xmx1600m (م إلزامي وإلا فإنه سيؤدي إلى خطأ آخر يعمل "الكومة الأولية الصغيرة جدًا").

لا توجد فكرة عما إذا كان هذا يحدث مع منتجات AV الأخرى ولكن من المفترض أن يحدث هذا لأن برنامج AV يحتفظ بكتلة صغيرة من الذاكرة في كل مساحة عنوان، وبالتالي يمنع تخصيصًا واحدًا كبيرًا حقًا.

عملت وسيطات VM بالنسبة لي في الكسوف.إذا كنت تستخدم الإصدار 3.4 من Eclipse، فقم بما يلي

اذهب إلى Run --> Run Configurations --> ثم حدد المشروع ضمن البناء المخضرم --> ثم حدد علامة التبويب "JRE" --> ثم أدخل -Xmx1024m.

بدلا من ذلك يمكنك القيام به Run --> Run Configurations --> select the "JRE" tab --> ثم أدخل -Xmx1024m

يجب أن يؤدي هذا إلى زيادة كومة الذاكرة لكافة البنيات/المشاريع.حجم الذاكرة المذكورة أعلاه هو 1 جيجابايت.يمكنك تحسين الطريقة التي تريدها.

نعم مع -Xmx يمكنك تكوين المزيد من الذاكرة لـ JVM الخاص بك.للتأكد من أنك لا تتسرب أو تضيع الذاكرة.خذ تفريغ الكومة واستخدمها محلل ذاكرة الكسوف لتحليل استهلاك الذاكرة الخاصة بك.

أود أن أضيف توصيات من أوراكل استكشاف الأخطاء وإصلاحها شرط.

استثناء في موضوع thread_name: java.lang.OutOfMemoryError:مساحة كومة جافا

تشير رسالة التفاصيل مساحة كومة Java إلى أنه لا يمكن تخصيص الكائن في كومة Java.لا يعني هذا الخطأ بالضرورة حدوث تسرب للذاكرة

الأسباب المحتملة:

  1. مشكلة تكوين بسيطة, ، حيث يكون حجم الكومة المحدد غير كافٍ للتطبيق.

  2. يحتفظ التطبيق بمراجع للكائنات عن غير قصد, ، وهذا يمنع الكائنات من تجميع البيانات المهملة.

  3. الاستخدام المفرط للنهائيات.

ينشأ مصدر محتمل آخر لهذا الخطأ مع التطبيقات التي تستخدم أدوات الإنهاء بشكل مفرط.إذا كان للفئة طريقة إنهاء، فلن تتم استعادة المساحة الخاصة بالكائنات من هذا النوع في وقت تجميع البيانات المهملة

بعد جمع القمامة, ، يتم وضع الكائنات في قائمة الانتظار وضع اللمسات النهائية, ، والذي يحدث في وقت لاحق. الصيغ النهائية يتم تنفيذها بواسطة مؤشر ترابط خفي يخدم قائمة انتظار الإنهاء.إذا Finalizer لا يمكن لمؤشر الترابط مواكبة قائمة انتظار الإنهاء، ومن ثم قد تمتلئ كومة Java وهذا النوع من خطأ عدم وجود ذاكرة كافية سيتم طرح الاستثناء.

أحد السيناريوهات التي يمكن أن تسبب هذا الموقف هو عند إنشاء التطبيق المواضيع ذات الأولوية العالية التي تسبب وضع اللمسات النهائية قائمة الانتظار لزيادة بمعدل أسرع من المعدل الذي يخدم فيه مؤشر ترابط Finalizer قائمة الانتظار هذه.

اتبع الخطوات التالية:

  1. يفتح catalina.sh من القط/بن.

  2. قم بتغيير JAVA_OPTS إلى

    JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m 
    -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m 
    -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
    
  3. أعد تشغيل القط الخاص بك

طريقة سهلة للحل OutOfMemoryError في جافا هو زيادة الحد الأقصى لحجم الكومة باستخدام خيارات JVM -Xmx512M, سيؤدي هذا إلى حل مشكلة OutOfMemoryError على الفور.هذا هو الحل المفضل لدي عندما أحصل على OutOfMemoryError في Eclipse أو Maven أو ANT أثناء إنشاء المشروع لأنه بناءً على حجم المشروع، يمكنك بسهولة نفاد الذاكرة.

فيما يلي مثال على زيادة الحد الأقصى لحجم الكومة لـ JVM، ومن الأفضل أيضًا الاحتفاظ بنسبة -Xmx إلى -Xms إما 1:1 أو 1:1.5 إذا كنت تقوم بتعيين حجم الكومة في تطبيق Java الخاص بك.

export JVM_ARGS="-Xms1024m -Xmx1024m"

الرابط المرجعي

بشكل افتراضي للتطوير، يستخدم JVM حجمًا صغيرًا وتكوينًا صغيرًا للميزات الأخرى المتعلقة بالأداء.ولكن بالنسبة للإنتاج يمكنك ضبطه على سبيل المثال.(بالإضافة إلى ذلك، يمكن أن يوجد تكوين خاص بخادم التطبيق) -> (إذا لم تكن هناك ذاكرة كافية لتلبية الطلب ووصلت الكومة بالفعل إلى الحد الأقصى للحجم، فسيحدث خطأ OutOfMemoryError)

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size
-Xss<size>        set java thread stack size

-XX:ParallelGCThreads=8
-XX:+CMSClassUnloadingEnabled
-XX:InitiatingHeapOccupancyPercent=70
-XX:+UnlockDiagnosticVMOptions
-XX:+UseConcMarkSweepGC
-Xms512m
-Xmx8192m
-XX:MaxPermSize=256m (in java 8 optional)

على سبيل المثال:على منصة Linux لإعدادات وضع الإنتاج المفضلة.

بعد التنزيل وتكوين الخادم بهذه الطريقة http://www.ehowstuff.com/how-to-install-and-setup-Apache-tomcat-8-on-centos-7-1-rhel-7/

1. قم بإنشاء ملف setenv.sh في المجلد /opt/tomcat/bin/

   touch /opt/tomcat/bin/setenv.sh

2. افتح هذه المعلمات واكتبها لتحديد الوضع المفضل.

nano  /opt/tomcat/bin/setenv.sh 

export CATALINA_OPTS="$CATALINA_OPTS -XX:ParallelGCThreads=8"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS="$CATALINA_OPTS -XX:InitiatingHeapOccupancyPercent=70"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UnlockDiagnosticVMOptions"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseConcMarkSweepGC"
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx8192m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=256M"

3.service tomcat restart

لاحظ أن JVM يستخدم ذاكرة أكبر من الكومة فقط.على سبيل المثال طرق Java ، يتم تخصيص مداخن مؤشرات الترابط والمقابض الأصلية في الذاكرة منفصلة عن الكومة ، وكذلك هياكل البيانات الداخلية JVM.

لقد واجهت نفس المشكلة من حجم كومة جافا.

لدي حلان إذا كنت تستخدم Java 5(1.5).

  1. فقط قم بتثبيت jdk1.6 وانتقل إلى تفضيلات Eclipse وقم بتعيين مسار jre لـ jav1 1.6 كما قمت بالتثبيت.

  2. تحقق من وسيطة VM الخاصة بك واتركها كما هي.فقط أضف سطرًا واحدًا أدناه لجميع الوسائط الموجودة في وسيطات VM كـ -XMS512M -XMX512M -xx: maxpermsize = ... M (192m).

أعتقد أنه سينجح...

قرأت في مكان آخر أنه يمكنك تجربتها - التقاط java.lang.OutOfMemoryError وفي كتلة الالتقاط، يمكنك تحرير جميع الموارد التي تعلم أنها قد تستخدم قدرًا كبيرًا من الذاكرة، وتغلق الاتصالات وما إلى ذلك، ثم قم بإجراء System.gc() ثم أعد محاولة كل ما كنت ستفعله.

هناك طريقة أخرى، على الرغم من أنني لا أعرف ما إذا كان هذا سينجح أم لا، لكنني حاليًا أختبر ما إذا كان سيعمل على طلبي.

الفكرة هي القيام بجمع البيانات المهملة عن طريق استدعاء System.gc() المعروف بزيادة الذاكرة الحرة.يمكنك الاستمرار في التحقق من ذلك بعد تنفيذ رمز التهام الذاكرة.

//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);

Runtime runtime = Runtime.getRuntime();

if(runtime.freeMemory()<minRunningMemory)
 System.gc();

إذا كنت بحاجة إلى مراقبة استخدام الذاكرة الخاصة بك في وقت التشغيل، فإن java.lang.management عروض الحزمة MBeans التي يمكن استخدامها لمراقبة تجمعات الذاكرة في جهاز VM الخاص بك (على سبيل المثال، مساحة عدن، والجيل الثابت وما إلى ذلك)، وكذلك سلوك جمع البيانات المهملة.

ستختلف مساحة الكومة المجانية التي تم الإبلاغ عنها بواسطة MBeans بشكل كبير اعتمادًا على سلوك GC، خاصة إذا كان التطبيق الخاص بك ينشئ الكثير من الكائنات التي أصبحت لاحقًا GC-ed.أحد الأساليب الممكنة هو مراقبة مساحة الكومة الحرة بعد كل GC كاملة، والتي قد تتمكن من استخدامها لاتخاذ قرار بشأن تحرير الذاكرة عن طريق الكائنات المستمرة.

في النهاية، أفضل رهان لك هو الحد من الاحتفاظ بالذاكرة قدر الإمكان بينما يظل الأداء مقبولًا.كما أشار تعليق سابق، الذاكرة دائمًا محدودة، ولكن يجب أن يكون لتطبيقك استراتيجية للتعامل مع استنفاد الذاكرة.

لاحظ أنه إذا كنت بحاجة إلى ذلك في حالة النشر، فكر في استخدام Java WebStart (مع إصدار "ondisk"، وليس إصدار الشبكة - ممكن في Java 6u10 والإصدارات الأحدث) لأنه يسمح لك بتحديد الوسائط المتنوعة لـ JVM في تقاطع طريقة المنصة.

وإلا فستحتاج إلى مشغل خاص بنظام التشغيل يقوم بتعيين الوسائط التي تحتاجها.

إذا كانت هذه المشكلة تحدث في Wildfly 8 وJDK1.8، فسنحتاج إلى تحديد إعدادات MaxMetaSpace بدلاً من إعدادات PermGen.

على سبيل المثال، نحتاج إلى إضافة التكوين أدناه في ملف setenv.sh الخاص بـ Wildfly.JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=256M"

لمزيد من المعلومات، يرجى التحقق قضية كومة الذبابة البرية

فيما يتعلق بـ netbeans، يمكنك تعيين الحد الأقصى لحجم الكومة لحل المشكلة.

انتقل إلى "تشغيل"، ثم --> "تعيين تكوين المشروع" --> "تخصيص" --> "تشغيل" النافذة المنبثقة --> "خيار VM" --> املأ "-Xms2048m -Xmx2048m" .

إذا واصلت تخصيص المراجع للكائن والاحتفاظ بها، فسوف تملأ أي قدر من الذاكرة لديك.

أحد الخيارات هو إغلاق ملف شفاف وفتحه عند تبديل علامات التبويب (تحتفظ فقط بمؤشر إلى الملف، وعندما يقوم المستخدم بتبديل علامة التبويب، يمكنك إغلاق جميع الكائنات وتنظيفها...سيجعل تغيير الملف أبطأ ...لكن...) وربما يحتفظ بثلاثة أو أربعة ملفات فقط في الذاكرة.

الشيء الآخر الذي يجب عليك فعله هو، عندما يفتح المستخدم ملفًا، ويحمله، ويعترض أي OutOfMemoryError، ثم (نظرًا لعدم إمكانية فتح الملف) قم بإغلاق هذا الملف، وتنظيف كائناته وتحذير المستخدم بأنه يجب عليه إغلاقه غير مستخدم ملفات.

إن فكرتك المتمثلة في توسيع الذاكرة الافتراضية ديناميكيًا لا تحل المشكلة، لأن الجهاز محدود الموارد، لذا يجب أن تكون حذرًا وتتعامل مع مشكلات الذاكرة (أو على الأقل، كن حذرًا معها).

بعض التلميحات التي رأيتها مع تسرب الذاكرة هي:

--> ضع في اعتبارك أنه إذا وضعت شيئًا ما في مجموعة ثم نسيته بعد ذلك، فلا يزال لديك إشارة قوية إليه، لذا قم بإبطال المجموعة أو تنظيفها أو القيام بشيء ما بها...إذا لم يكن الأمر كذلك فستجد صعوبة في العثور على تسرب للذاكرة.

--> ربما، استخدام المجموعات ذات المراجع الضعيفة (weakhashmap...) يمكن أن يساعد في حل مشكلات الذاكرة، لكن أنت يجب كن حذرًا في ذلك، فقد تجد أن الشيء الذي تبحث عنه قد تم جمعه.

--> فكرة أخرى وجدتها هي تطوير مجموعة ثابتة يتم تخزينها على كائنات قاعدة البيانات الأقل استخدامًا والتي يتم تحميلها بشفافية.ربما يكون هذا هو النهج الأفضل ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top