كيفية التحقّق من استخدام الذاكرة باستخدام أدوات Unity

في نظام التشغيل Android، يمثّل الحد الأدنى لحدود الذاكرة في أداة تحديد حدود الذاكرة (الإصدار 17 من نظام التشغيل Android والإصدارات الأحدث) وقيمة قياس أداء مؤشر الذاكرة الحيوي في Google Play Console ذاكرة RSS المجهولة + مساحة الإبدال. تمثّل هذه القيمة مستوى ضغط الذاكرة الفعلية الذي يشغله التطبيق، وهي مقياس مهم يجب تتبُّعه لضمان استقرار التطبيق.

في الوقت الحالي، يصعب قياس استخدام الذاكرة الذي يتطابق تمامًا مع "RSS مجهول الهوية + مساحة التبديل"، سواء في وقت التشغيل أو بشكل ثابت داخل Unity Engine.

لحلّ هذه المشكلة، توضّح هذه الصفحة كيفية تتبُّع قيمة خلاصة RSS المجهولة الهوية + التبديل بموثوقية عالية من خلال التقريب باستخدام Unity Profiler وProfileRecorder API وUnity Memory Profiler في بيئة Unity Engine.

التحقّق من استخدام الذاكرة في وقت التشغيل

في Unity، قد يكون من الصعب قياس استخدام الذاكرة الدقيق لحجم مجموعة البيانات الدائمة المجهولة + مساحة الإبدال في Android مباشرةً في وقت التشغيل بدون تكلفة إضافية. ومع ذلك، يمكنك تقدير هذه القيمة بدقة (في حدود تفاوت% 10 تقريبًا) باستخدام واجهات برمجة التطبيقات المضمّنة في أداة Profiler من Unity.

الطريقة 1: استخدام أداة Profiler

يمكنك تقدير إجمالي استخدام الذاكرة من خلال جمع القيم التي تعرضها واجهات برمجة التطبيقات التالية الخاصة بأداة Profiler:

using UnityEngine;
using UnityEngine.Profiling;

public class MemoryMonitor : MonoBehaviour
{
    public long GetEstimatedMemoryUsageBytes()
    {
        long totalReserved = Profiler.GetTotalReservedMemoryLong();
        long monoHeapSize = Profiler.GetMonoHeapSizeLong();

        return totalReserved + monoHeapSize;
    }
}

الطريقة 2: استخدام فئة ProfilerRecorder

يمكنك تتبُّع مقياسَي إجمالي الذاكرة المحجوزة وذاكرة Gfx المحجوزة باستخدام ProfilerRecorder:

  • في إصدارات التطوير: احسب إجمالي الذاكرة المحجوزة - ذاكرة Gfx المحجوزة.

  • في إصدارات Release: استخدِم إجمالي الذاكرة المحجوزة مباشرةً.

using Unity.Profiling;
using UnityEngine;

public class MemoryMonitor : MonoBehaviour
{
    ProfilerRecorder totalRecorder;

#if DEVELOPMENT_BUILD
    ProfilerRecorder gfxRecorder;
#endif

    private void OnEnable()
    {
        totalRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");

#if DEVELOPMENT_BUILD
        gfxRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Gfx Reserved Memory");
#endif
    }

    private void OnDisable()
    {
        totalRecorder.Dispose();

#if DEVELOPMENT_BUILD
        gfxRecorder.Dispose();
#endif
    }

    public long GetEstimatedMemoryUsageBytes()
    {
#if DEVELOPMENT_BUILD
        if (totalRecorder.Valid && gfxRecorder.Valid)
        {
            return totalRecorder.LastValue - gfxRecorder.LastValue;
        }
#else
        if (totalRecorder.Valid)
        {
            return totalRecorder.LastValue;
        }
#endif
        return 0;
    }
}

القيود:

  • لا يمكن تتبُّع عمليات تخصيص الذاكرة التي تتجاوز "مدير الذاكرة" في Unity (مثل NativeMalloc(IntPtr size)) باستخدام واجهات برمجة التطبيقات هذه.

  • قد لا تكون واجهات برمجة التطبيقات هذه متاحة حسب إصدار Unity.

تحليل تفاصيل استخدام الذاكرة (تحليل ثابت)

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

Unity Memory Profiler

لإجراء تحليل تفصيلي للذاكرة وتحسين لعبتك، استخدِم حزمة Unity Memory Profiler. للعثور على العناصر المتوافقة مع استخدام ذاكرة RSS المجهولة + مساحة الإبدال في نظام التشغيل Android OS:

  1. التقِط لقطة باستخدام أداة Unity Memory Profiler.
  2. افتح اللقطة وانتقِل إلى كل المعلومات المحفوظة > الذاكرة المقيمة على الجهاز.
  3. احسب مجموع العناصر التالية:

    • لم يتم تتبُّعه
    • وقت تشغيل Android
    • الإعلانات المدمجة مع المحتوى
    • مُدار
    مقاييس الذاكرة التي يمكن عرضها عند ضبطها على "الذاكرة المقيمة" في "أداة تحليل الذاكرة" في Unity
    الشكل 1. يتم تخزين "أوصاف الذاكرة" في الذاكرة المقيمة

يعمل المجموع الكلي كبديل عملي عن ذاكرة RSS المجهولة + مساحة الإبدال في نظام التشغيل Android، ما يقدّم إحصاءات قابلة للتنفيذ لتحليل ذاكرة الألعاب.

القيود:

  • في حال الضغط الشديد على الذاكرة، قد يضغط نظام التشغيل Android صفحات الذاكرة النشطة أو يبدّلها لإتاحة مساحة في ذاكرة الوصول العشوائي. وبما أنّ أداة Unity Memory Profiler لا يمكنها تتبُّع الذاكرة المبدَّلة، قد تحدث اختلافات في سيناريوهات الاستخدام العالي للذاكرة.

  • قد تكون هذه الميزات محدودة حسب إصدار Unity.

أمثلة على نصوص C# البرمجية

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

  • يوضّح النص البرمجي AndroidProcessStats كيفية استخدام JNI (واجهة Java الأصلية) للربط بواجهات برمجة التطبيقات ActivityManager في Android، كما يوفّر وظائف لجلب العمليات قيد التشغيل وأهميتها وحالتها على مستوى نظام التشغيل. ويحتوي أيضًا على طرق بسيطة لقراءة إحصاءات الذاكرة مباشرةً من نظام ملفات Linux /proc.
  • يوضّح النص البرمجي GameMemoryMonitor كيفية ربط هذه المعلومات بعملية المراقبة وتصحيح الأخطاء بشكل مستمر، بما في ذلك كيفية طلب بيانات من واجهات برمجة التطبيقات لنظام Android في سلسلة محادثات في الخلفية لمنع زيادة الحمل على الأداء (لأنّ استخدام JNI وطلب بيانات الذاكرة قد يكون مكلفًا)، وكيفية الربط بأحداث مراحل النشاط، مثل OnApplicationPause، لتتبُّع التغييرات في الذاكرة عند تشغيل التطبيق في الخلفية أو استئنافه.

لاستخدام هذه الأدوات، أضِف كلا البرنامجين إلى مجلد "مواد العرض"، واربط البرنامج GameMemoryMonitor بعنصر GameObject في المشهد.

تقييم أكثر دقة

للتحقّق من قيم ذاكرة RSS المجهولة + مساحة الإبدال الدقيقة لنظام التشغيل Android، استخدِم أداة Perfetto. يتيح لك هذا الإجراء قياس استخدام الذاكرة الدقيق على مستوى النظام وتحليل حجم الذاكرة التي تستخدمها لعبتك بشكل شامل.

واجهة مستخدم Perfetto تعرض ذاكرة RSS المجهولة ومساحة الإبدال واستعلام المجموع.
الشكل 2. واجهة مستخدم Perfetto تعرض ذاكرة RSS المجهولة ومساحة الإبدال ومجموع استعلاماتهما