ما هي استراتيجياتك للحفاظ على استخدام الذاكرة منخفضة؟

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

سؤال

روبي إنه حقًا متعطش للذاكرة - ولكنه يستحق أيضًا كل جزء منه.

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

يحرر:لقد وجدت مقالة جميلة حول هذا الموضوع هنا - قديمة ولكنها لا تزال مثيرة للاهتمام.

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

المحلول

  1. اختر هياكل التاريخ التي تمثل تمثيلات فعالة، وقياسها بشكل جيد، وافعل ما تحتاجه.
  2. استخدم الخوارزميات التي تعمل باستخدام هياكل بيانات فعالة بدلاً من الهياكل المتضخمة ولكن الأسهل.
  3. ننظر في مكان آخر.تحتوي روبي على جسر C ومن الأسهل بكثير أن تكون واعيًا بالذاكرة في لغة C مقارنةً بـ Ruby.

نصائح أخرى

لقد وجدت Phusion's Ruby Enterprise Edition (شوكة من Ruby الرئيسية مع مجموعة القمامة المحسنة كثيرًا) لإحداث فرق كبير في استخدام الذاكرة...بالإضافة إلى ذلك، فقد جعلوا من السهل جدًا تثبيته (وإزالته، إذا وجدت الحاجة).

يمكنك معرفة المزيد وتنزيله على موقعهم على الانترنت.

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

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

قد تتمكن من تشغيل التطبيق الخاص بك على JVM باستخدام JRuby - إن Ruby VM ليس متقدمًا حاليًا مثل JVM لإدارة الذاكرة وجمع البيانات المهملة.يضيف الإصدار 1.9 العديد من التحسينات وهناك أجهزة افتراضية بديلة قيد التطوير أيضًا.

إن مطوري روبي محظوظون جدًا لأنهم لا يضطرون إلى إدارة الذاكرة بأنفسهم.

انتبه إلى أن روبي تخصص كائنات، على سبيل المثال شيء بسيط مثل

100.times{ 'foo' }

يخصص 100 كائن سلسلة (السلاسل قابلة للتغيير ويتطلب كل إصدار تخصيص الذاكرة الخاصة به).

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

على سبيل المثال، يؤدي إنشاء كائن تجزئة إلى تخصيص أكثر من مجرد كائن

{'joe' => 'male', 'jane' => 'female'}

لا يخصص كائنًا واحدًا ولكن 7.(تجزئة واحدة، 4 سلاسل + سلسلتين رئيسيتين)

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

مثال: في مكان ما في تطبيقك، يمكنك تطبيق to_sym على اسم المستخدم مثل:

hash[current_user.name.to_sym] = something

عندما يكون لديك مئات المستخدمين، قد يكون هذا أمرًا جيدًا، ولكن ماذا يحدث إذا كان لديك مليون مستخدم؟وهنا الأرقام:

ruby-1.9.2-head >
# Current memory usage : 6608K
# Now, add one million randomly generated short symbols
ruby-1.9.2-head > 1000000.times { (Time.now.to_f.to_s).to_sym }

# Current memory usage : 153M, even after a Garbage collector run.

# Now, imagine if symbols are just 20x longer than that ?
ruby-1.9.2-head > 1000000.times { (Time.now.to_f.to_s * 20).to_sym }
# Current memory usage : 501M

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

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

وإليكم بعض الروابط في هذا الشأن:

http://merbist.com

http://blog.monitis.com

  1. عند نشر تطبيق ويب Rails/Rack، استخدم REE أو أي مترجم آخر سهل النسخ عند الكتابة.
  2. قم بتعديل جامع القمامة (انظر https://www.engineyard.com/blog/tuning-the-garbage-collector-with-ruby-1-9-2 على سبيل المثال)
  3. حاول تقليل عدد المكتبات/الجواهر الخارجية التي تستخدمها نظرًا لأن التعليمات البرمجية الإضافية تستخدم الذاكرة.
  4. إذا كان لديك جزء من تطبيقك يستهلك الكثير من الذاكرة، فربما يكون من المفيد إعادة كتابته بامتداد C أو إكماله عن طريق استدعاء برامج أخرى/أسرع/أفضل محسنة (إذا كان عليك معالجة كميات هائلة من البيانات النصية، فربما عليك يمكن استبدال هذا الرمز باستدعاءات لـ grep أو awk أو sed وما إلى ذلك)

أنا لست مطور روبي ولكن أعتقد أن بعض التقنيات والأساليب تنطبق على أي لغة:

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

استخدم معالجة الأخطاء بشكل لائق (حاول التقاطها أخيرًا) للتأكد من إغلاق الكائنات والاتصالات

عند التعامل مع مجموعات البيانات، قم بإرجاع الحد الأدنى الضروري فقط

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

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

الشيء الوحيد الذي كان لدينا على الإطلاق والذي كان يستحق القلق بشأنه هو RMagick.

الحل هو التأكد من أنك تستخدم الإصدار 2 من RMagick، ثم اتصل Image#destroy! عند الانتهاء من استخدام صورتك

تجنب الكود مثل هذا:

str = ''
veryLargeArray.each do |foo|
  str += foo
  # but str << foo is fine (read update below)
end

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

بدلا من ذلك، استخدم Array#join:

str = veryLargeArray.join('')

يتم تنفيذ ذلك في لغة C بكفاءة عالية ولا يتحمل تكاليف إنشاء السلسلة.

تحديث:جوناس على حق في التعليق أدناه.تحذيري يحمل ل += لكن لا <<.

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

أنا أستخدم بايثون، ولكن أعتقد أن الاستراتيجيات متشابهة.

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

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

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

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

عندما يكون ذلك ممكنًا، استخدم المصفوفات بدلاً من بنيات البيانات الأخرى.حاول ألا تستخدم العوامات عندما تكون الأعداد الصحيحة مناسبة.

كن حذرًا عند استخدام أساليب الأحجار الكريمة/المكتبة.قد لا تكون الذاكرة الأمثل.على سبيل المثال، تحتوي فئة Ruby PG::Result على أسلوب "values" الذي لم يتم تحسينه.سوف يستخدم الكثير من الذاكرة الإضافية.لم أبلغ عن هذا بعد.

استبدال تنفيذ malloc(3) ل jemaloc سوف يقلل على الفور من استهلاك الذاكرة لديك بنسبة تصل إلى 30%.لقد قمت بإنشاء جوهرة "jemalloc" لتحقيق ذلك على الفور.

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

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

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

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