سؤال

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

مثال: هناك 5 صفائف مخصصة 96 ميجابايت (200x200x200، 12 بايت من البيانات في كل إدخال) ويحتاج البرنامج إلى استبدالها ب 210x210x210 (111 ميغابايت). يفعل ذلك بطريقة مماثلة لهذا:

array1 = new Vector3[210,210,210];

حيث يتم استخدام Array1-Array5 نفس الحقول المستخدمة سابقا. يجب أن يقوم ذلك بتعيين المصفوفات القديمة كمرشحين لجمع القمامة ولكن يبدو أن GC لا يتصرف بسرعة كافية ويترك المصفوفات القديمة المخصصة قبل تخصيص تلك الجديدة - والتي تسبب Oom - في حين أنهم إذا أطلق سراحهم قبل المخصصات الجديدة كافية.

ما أبحث عنه هو وسيلة للقيام بشيء مثل هذا:

GC.Collect(array1) // this would set the reference to null and free the memory
array1 = new Vector3[210,210,210];

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

هل هناك طريقة مناسبة للقيام بذلك؟

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

المحلول

هذه ليست إجابة دقيقة على السؤال الأصلي، "كيفية إجبار GC"، ومع ذلك، أعتقد أنه سيساعدك في إعادة النظر في مشكلتك.

بعد رؤية تعليقك،

  • وضع gc.collect ()؛ يبدو أنه يساعد، ومعطلته لا يزال لا يحل المشكلة تماما - لسبب ما لا يزال البرنامج يتعطل عندما يتم تخصيص حوالي 1.3 جيجابايت (أنا أستخدم system.gc.gg.gettotalemory (خطأ)؛ للعثور على المبلغ الحقيقي المخصص).

سوف أشك في أنك قد يكون تجزئة الذاكرة. وبعد إذا كان الكائن كبيرا (85000 بايت تحت .NET 2.0 CLR إذا كنت أتذكر بشكل صحيح، فأنا لا أعرف ما إذا كان قد تم تغييره أم لا)، وسيتم تخصيص الكائن في كومة خاصة، كائن كبير كومة (لوه). وبعد هل ترغب GC في استعادة الذاكرة التي تستخدمها كائنات غير قابلة للوصول في LOH، ومع ذلك، لا يؤدي الضغط، في LOH كما يفعل بأكواك أخرى (GEN0، GEN1، و GEN2)، بسبب الأداء.

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

أستطيع أن أفكر في الحلول في هذه اللحظة.

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

نصائح أخرى

يبدو أنك تدير قضية تجزئة LOH (كائن كائن كبير).

كائن كبير كومة

CLR داخل كائن كبير الكومة كشف

يمكنك التحقق لمعرفة ما إذا كنت تواجه مشكلات تجزئة LOH باستخدام SOS

افحص هذا سؤال للحصول على مثال على كيفية استخدام SOS لتفقد اللوحة.

إجبار مجموعة القمامة ليست دائما فكرة جيدة (يمكن أن تعزز في الواقع حياة الكائنات في بعض الحالات). إذا كان عليك، فستستخدم:

array1 = null;
GC.Collect();
array1 = new Vector3[210,210,210];

أليس هذا مجرد كائن كبير كومة التشرذنية؟ الكائنات> يتم تخصيص 85000 بايت على كومة الكائنات الكبرى الكبيرة. يحرر GC الفضاء في هذه الكومة ولكن لا تقلص أبدا الكائنات المتبقية. يمكن أن يؤدي ذلك إلى الذاكرة المجاورة غير المتجاورة لتخصيص كائن كبير بنجاح.

آلان.

إذا اضطررت إلى التكهن أنك لا تكون المشكلة ليست في الحقيقة أنك تذهب من Vector3 [200،200،200] إلى Vector3 [210،210،210] ولكن على الأرجح لديك خطوات سابقة مماثلة قبل هذا:

 أي // أولا لديك متجه 3 [10،10،10]؛ // ثم Vector3 [20،20،20]؛ // ثم ربما المتجهة 3 [30،30،30]؛ // .. وهلم جرا .. // ... // ثم Vector3 [200،200،200]؛ // وفي النهاية يمكنك تجربة Vector3 [210،210،210] // وأنت تحصل على OutofMemoryException ..

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

لذلك، بدلا من أعلاه، يكون لديك شيء من هذا القبيل:

 // first start with an arbitrary size
 Vector3[64,64,64];
 // then double that
 Vector3[128,128,128];
 // and then.. so in thee steps you go to where otherwise 
 // it would have taken you 20..
 Vector3[256,256,256];

قد لا يتم جمعهم لأنهم يشاركون إلى مكان ما لا تتوقعهم.

كاختبار، حاول تغيير مراجعك إلى الضعف بدلا من ذلك ومعرفة ما إذا كان هذا يحل مشكلة OOM الخاصة بك. إذا لم يكن الأمر كذلك فأنت تشير إليهم في مكان آخر.

أفهم ما تحاول القيام به والضغط من أجل جمع القمامة الفوري ربما لا يكون النهج الصحيح (نظرا لأن GC هو دقيق في طرقه وسريعة الغضب).

ومع ذلك، إذا كنت يريد هذه الوظيفة، لماذا لا تنشئها؟

public static void Collect(ref object o)
{
    o = null;
    GC.Collect();
}

يعزز استثناء OutofMemory داخليا دورة GC تلقائيا مرة واحدة ويحاول التخصيص مرة أخرى قبل إلقاء الاستثناء الخاص بك بالفعل. الطريقة الوحيدة التي يمكن أن تواجه استثناءاتها الخارجية إذا كنت تحمل إشارات إلى الكثير من الذاكرة. قم بإلغاء تحديد المراجع في أقرب وقت ممكن عن طريق تعيينها NULL.

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

حاول تخصيصها كصفيف خشن - Vector3 [210] [210] [210] [210] - الذي ينظم المصفوفات حول الذاكرة بدلا من كتلة واحدة، ومعرفة ما إذا كان ذلك يحسن الأمور

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

يمكنك التحقق من ذلك هو الحال عن طريق كسر المصحح عند نقطة OOM والحصول على تفريغ، وتقديم تفريغ هذا إلى MS من خلال علة الاتصال (http://connnect.microsoft.com.) ستكون بداية رائعة.

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

لا أعرف ما هي سياسة تقاسم مقالب الذاكرة على Stackoverflow، لكنني سأكون سعيدا بالنظر إلى أن تفهم مشكلتك أكثر.

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