سؤال

يبدو أن Doctrine تستهلك ما يزيد عن 4 ميغابايت من ذاكرة الوصول العشوائي (RAM) لتنفيذ استعلام واحد بسيط:

print memory_get_peak_usage()." <br>\n";
$q = Doctrine_Query::create()
    ->from('Directories d')
    ->where('d.DIRECTORY_ID = ?', 5);

$dir = $q->fetchOne();
print $dir['name']." ".$dir['description']."<br>\n";

print memory_get_peak_usage()." <br>\n";

/***************  OUTPUT:  **************************

6393616
testname testdescription
10999648

/***************************************************/

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

هل من المحتمل أن يكون هناك خطأ ما في طريقة إعداد النظام، أم أن هذا الاستخدام القياسي للذاكرة في Doctrine؟

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

المحلول

مما أستطيع رؤيته، لا يبدو أن رمزك خاطئ...


كاختبار، قمت بإعداد مثال سريع، مع جدول بسيط للغاية (أربعة حقول فقط).

هنا هو الكود ذو الصلة:

var_dump(number_format(memory_get_peak_usage()));

$test = Doctrine::getTable('Test')->find(1);

var_dump(number_format(memory_get_peak_usage()));

عند القيام بذلك، لدي هذا النوع من الإخراج:

string '1,316,088' (length=9)
string '2,148,760' (length=9)

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


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

$test = Doctrine::getTable('Test')->find(1, Doctrine::HYDRATE_ARRAY);

ولكن، في هذه الحالة، لا يحدث فرقًا كبيرًا، في الواقع :-( :

string '1,316,424' (length=9)
string '2,107,128' (length=9)

فقط 40 كيلو بايت من الاختلاف - حسنًا، مع كائنات أكبر/خطوط أكثر، قد تظل فكرة جيدة...


وفي دليل الفقه صفحة تسمى تحسين الأداء ;ربما يمكن أن تساعدك، وخاصة بالنسبة لهذه الأقسام:


أوه بالمناسبة :لقد أجريت هذا الاختبار على PHP 5.3.0؛ربما هذا يمكن أن يكون له تأثير على مقدار الذاكرة المستخدمة ...

نصائح أخرى

أتفق مع إجابة romanb - يعد استخدام ذاكرة التخزين المؤقت OpCode أمرًا ضروريًا عند استخدام libs/إطارات العمل الكبيرة.

مثال يتعلق بالتخزين المؤقت لـ OpCode

لقد اعتمدت مؤخرًا استخدام Doctrine مع Zend Framework وكان لدي فضول بشأن استخدام الذاكرة - لذا، مثل OP، قمت بإنشاء طريقة تستخدم معايير مشابهة لاختبار OPs وقمت بتشغيلها كاختبار شامل لمعرفة ما سيكون عليه استخدام ذاكرة الذروة لـ ZF + Doctrine يكون.

حصلت على النتائج التالية:

النتيجة بدون APC:

10.25 megabytes
RV David
16.5 megabytes

النتيجة مع APC:

3 megabytes
RV David
4.25 megabytes

يُحدث التخزين المؤقت لرمز التشغيل فرقًا كبيرًا جدًا.

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

واستهلاك الذاكرة يأتي من جميع الفئات التي يتم تحميلها على الطلب من خلال autoloading.

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

و4MB مع المثال الخاص بك بسيطة الروائح حقا مثل عدم APC، وإلا فإنه سيكون حقا مرتفعة بعض الشيء.

والحذر مع fetchOne () على مذهب سؤال. سيكون لهذه الدعوة وظيفة لا إلحاق "الحد 1" على SQL

إذا كنت بحاجة فقط للحصول على سجل واحد من DB، فتأكد من:

$q->limit(1)->fetchOne() 

واستخدام الذاكرة هو تراجع هائل على جدول كبير.

ويمكنك أن ترى fetchOne () سوف تجلب من DB كمجموعة أولا ثم يعود العنصر الأول.

public function fetchOne($params = array(), $hydrationMode = null)
{
    $collection = $this->execute($params, $hydrationMode);

    if (is_scalar($collection)) {
        return $collection;
    }

    if (count($collection) === 0) {
        return false;
    }

    if ($collection instanceof Doctrine_Collection) {
        return $collection->getFirst();
    } else if (is_array($collection)) {
        return array_shift($collection);
    }

    return false;
}

توفر Doctrine دالة free()‎ في Doctrine_Record وDoctrine_Collection وDoctrine_Query والتي تزيل المراجع الدائرية الخاصة بهذه الكائنات، مما يحررها لجمع البيانات المهملة.مزيد من المعلومات..

لجعل استخدام الذاكرة أقل قليلاً، يمكنك محاولة استخدام الكود التالي:

  • $record->free(true) – سيجري عمليات تحرير عميقة، ويجري مكالمات مجانية () على جميع العلاقات أيضًا
  • $collection->free() – سيؤدي هذا إلى تحرير كافة مراجع المجموعة
  • Doctrine_Manager::connection()->clean()/clear() - اتصال التنظيف (وإزالة إدخالات خريطة الهوية)
  • استعلام $->مجاني()

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

  • ما هو إصدار Doctrine الذي تستخدمه؟
  • هل تستخدم أداة التحميل التلقائي؟

في Doctrine 1.1، يُطلق على سلوك التحميل التلقائي الافتراضي اسم "العدوانية"، مما يعني أنه يقوم بتحميل جميع فئات النموذج الخاصة بك حتى لو كنت تستخدم واحدًا أو اثنين فقط في أي طلب معين.سيؤدي تعيين هذا السلوك إلى "محافظ" إلى تقليل استخدام الذاكرة.

ولقد فعلت "daemonized" النصي بواسطة symfony 1.4 ووضع ما يلي توقف ذاكرة القص:

sfConfig::set('sf_debug', false);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top