سؤال

كيف يمكنك اكتشاف حجم كومة التطبيق بشكل برمجي لتطبيق Android؟

سمعت أن هناك وظيفة تقوم بذلك في إصدارات لاحقة من SDK. في أي حال ، أنا أبحث عن حل يعمل لـ 1.5 وما فوق.

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

المحلول

هناك طريقتان للتفكير في عبارة "حجم كومة التطبيق المتاح":

  1. ما مقدار الكومة التي يمكن أن يستخدمها تطبيقي قبل أن يتم تشغيل خطأ صعب؟ و

  2. كم كومة ينبغي استخدام تطبيقي ، بالنظر إلى قيود إصدار Android OS وأجهزة جهاز المستخدم؟

هناك طريقة مختلفة لتحديد كل مما سبق.

للبند 1 أعلاه: maxMemory()

التي يمكن استدعاؤها (على سبيل المثال ، في نشاطك الرئيسي onCreate() الطريقة) على النحو التالي:

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

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

للبند 2 أعلاه: getMemoryClass()

التي يمكن استدعاؤها على النحو التالي:

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

تخبرك هذه الطريقة تقريبًا كم عدد العدد ميغابايت من كومة التطبيق الخاص بك ينبغي استخدم إذا أراد أن تحترم بشكل صحيح حدود الجهاز الحالي ، وحقوق التطبيقات الأخرى في العمل دون إجبارها مرارًا وتكرارًا على onStop() / onResume() ركوب الدراجات أثناء إخراجها بوقاحة من الذاكرة بينما يأخذ تطبيق الفيل الخاص بك حمامًا في Android Jacuzzi.

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

للحصول على نسخة من Android ، maxMemory() عادة getMemoryClass() (أي ، ما يقرب من مليون مرة القيمة الأخيرة).

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

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

فيما يلي نتائج الاختبار التي توضح القيم التي تم إرجاعها بواسطة maxMemory() و getMemoryClass() بالنسبة لأربعة أجهزة مختلفة تقوم بتشغيل CyanogenMod ، باستخدام قيمتين مختلفين (محدد يدويًا) لكل منهما:

  • G1:
    • مع حجم كومة VM إلى 16 ميجابايت:
      • Maxmemory: 16777216
      • getMemoryclass: 16
    • مع حجم كومة VM إلى 24 ميجابايت:
      • Maxmemory: 25165824
      • getMemoryclass: 16
  • Moto Droid:
    • مع حجم كومة VM إلى 24 ميجابايت:
      • Maxmemory: 25165824
      • getMemoryClass: 24
    • مع حجم كومة VM إلى 16 ميجابايت:
      • Maxmemory: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • مع حجم كومة VM إلى 32 ميجابايت:
      • Maxmemory: 33554432
      • getMemoryClass: 32
    • مع حجم كومة VM إلى 24 ميجابايت:
      • Maxmemory: 25165824
      • getMemoryClass: 32
  • Viewsonic GTAB:
    • مع حجم كومة VM إلى 32:
      • Maxmemory: 33554432
      • getMemoryClass: 32
    • مع حجم كومة VM إلى 64:
      • Maxmemory: 67108864
      • getMemoryClass: 32

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

لهذا الجهاز ، ها هي النتائج:

  • Novo7
    • Maxmemory: 62914560
    • getMemoryClass: 60

أيضا (لكل كيشور في تعليق أدناه):

  • HTC X واحد
    • Maxmemory: 67108864
    • getMemoryclass: 64

و (لكل تعليق Akauppi):

  • Samsung Galaxy Core Plus
    • Maxmemory: (غير محدد في التعليق)
    • getMemoryclass: 48
    • hargemyclass: 128

لكل تعليق من cmcromance:

  • Galaxy S3 (Jelly Bean) كومة كبيرة
    • Maxmemory: 268435456
    • getMemoryclass: 64

و (تعليقات تينسنت):

  • LG Nexus 5 (4.4.3) طبيعي
    • Maxmemory: 201326592
    • getMemoryclass: 192
  • LG Nexus 5 (4.4.3) كومة كبيرة
    • Maxmemory: 536870912
    • getMemoryclass: 192
  • Galaxy Nexus (4.3) طبيعي
    • Maxmemory: 100663296
    • getMemoryclass: 96
  • Galaxy Nexus (4.3) كومة كبيرة
    • Maxmemory: 268435456
    • getMemoryclass: 96
  • Galaxy S4 Play Store Edition (4.4.2) عادي
    • Maxmemory: 201326592
    • getMemoryclass: 192
  • Galaxy S4 Play Store Edition (4.4.2) كومة كبيرة
    • Maxmemory: 536870912
    • getMemoryclass: 192

أجهزة أخرى

  • Huawei Nexus 6p (6.0.1) طبيعي
    • Maxmemory: 201326592
    • getMemoryclass: 192

لم أختبر هاتين الطريقتين باستخدام خيار Android الخاص: brageheap = "True" المتاح المتاح منذ قرص العسل ، ولكن بفضل cmcromance و tencent لدينا بعض قيم العينة الكبيرة ، كما ورد أعلاه.

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

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

لاحظ أن فئة الذاكرة على ما يبدو لا تحتاج إلى مضاعف 8 ميجابايت.

يمكننا أن نرى ما سبق أن getMemoryClass() النتيجة غير متوقعة لجهاز معين/تكوين نظام التشغيل ، بينما تتغير قيمة MaxMemory () عندما يتم تعيين الكومة بشكل مختلف بواسطة المستخدم.

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

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

أخيرًا ، إذا كنت تخطط للتغلب على عدد ميغابايت المحدد في getMemoryClass(), ، تتمثل نصيحتي في العمل لفترة طويلة وصعبة على توفير واستعادة حالة تطبيقك ، بحيث تكون تجربة المستخدم غير متقطعة تقريبًا إذا كان onStop() / onResume() تحدث الدورة.

في حالتي ، لأسباب تتعلق بالأداء ، أقصر تطبيقي على الأجهزة التي تعمل 2.2 وما فوق ، وهذا يعني أن جميع الأجهزة تقريبًا التي تعمل على تطبيقي ستحصل على MemoryClass من 24 أو أعلى. لذلك يمكنني التصميم لاحتلال ما يصل إلى 20 ميجابايت من الكومة وأشعر بالثقة الشديدة في أن تطبيقي سيلعب بشكل جيد مع التطبيقات الأخرى التي قد يعمل المستخدم في نفس الوقت.

ولكن سيكون هناك دائمًا عدد قليل من المستخدمين الجذريين الذين قاموا بتحميل إصدار 2.2 أو أعلى من Android على جهاز أقدم (على سبيل المثال ، G1). عندما تصادف مثل هذا التكوين ، من الناحية المثالية ، يجب عليك تخفيض استخدام ذاكرتك ، حتى لو maxMemory() يخبرك أنه يمكنك الذهاب إلى أعلى بكثير من 16 ميجابايت getMemoryClass() يخبرك أنك ينبغي الاستهداف. وإذا لم تتمكن من التأكد بشكل موثوق أن تطبيقك سيعيش ضمن هذه الميزانية ، فاحرص على الأقل على التأكد من ذلك onStop() / onResume() يعمل بسلاسة.

getMemoryClass(), ، كما أشار Diane Hackborn (Hackbod) أعلاه ، لا يتوفر إلا إلى API المستوى 5 (Android 2.0) ، وهكذا ، كما تنصح ، يمكنك افتراض أن الأجهزة المادية لأي جهاز يقوم بتشغيل إصدار سابق من نظام التشغيل مصمم لدعم التطبيقات على النحو الأمثل ، لا تزيد عن 16 ميجابايت.

على نقيض ذلك، maxMemory(), ، وفقا للوثائق ، يتوفر طوال الطريق إلى API المستوى 1. maxMemory(), ، في إصدار ما قبل 2.0 ، من المحتمل أن يعيد قيمة 16 ميجابايت ، لكنني فعل راجع أنه في إصدارات CyanogenMod (لاحقًا) ، يمكن للمستخدم تحديد قيمة الكومة تصل إلى 12 ميجابايت ، والتي من المفترض أن يؤدي maxMemory() القيمة ، حتى بالنسبة للإصدارات من نظام التشغيل قبل 2.0. قد تضطر حتى إلى رفض التشغيل في حالة غير مرجح أن يتم تعيين هذه القيمة أقل من 16 ميجابايت ، إذا كنت بحاجة إلى أكثر من maxMemory() يشير إلى أنه مسموح به.

نصائح أخرى

الرسمي API هو:

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

Debug.getNativeHeapSize() سأفعل الخدعة ، يجب أن أفكر. لقد كان هناك منذ 1.0 ، رغم ذلك.

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

إليك كيف تفعل ذلك:

الحصول على حجم كومة أقصى يمكن أن يستخدمه التطبيق:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

الحصول على مقدار الكومة التي يستخدمها تطبيقك حاليًا:

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

الحصول على مقدار الكومة التي يمكن أن يستخدمها تطبيقك الآن (الذاكرة المتاحة):

long availableMemory=maxMemory-usedMemory;

ولتنسيق كل واحد منهم بشكل جيد ، يمكنك استخدام:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 

هذا يعيد حجم كومة الحد الأقصى في البايتات:

Runtime.getRuntime().maxMemory()

كنت أستخدم ActivityManager.getMemoryClass () ولكن على CyanogenMod 7 (لم أختبره في مكان آخر) ، فإنه يعيد قيمة خاطئة إذا قام المستخدم بتعيين حجم الكومة يدويًا.

بعض العمليات أسرع من مدير الفضاء Java Heap. تأخير العمليات لبعض الوقت يمكن أن تحرر مساحة الذاكرة. يمكنك استخدام هذه الطريقة للهروب من خطأ في حجم الكومة:

waitForGarbageCollector(new Runnable() {
  @Override
  public void run() {

    // Your operations.
  }
});

/**
 * Measure used memory and give garbage collector time to free up some
 * space.
 *
 * @param callback Callback operations to be done when memory is free.
 */
public static void waitForGarbageCollector(final Runnable callback) {

  Runtime runtime;
  long maxMemory;
  long usedMemory;
  double availableMemoryPercentage = 1.0;
  final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
  final int DELAY_TIME = 5 * 1000;

  runtime =
    Runtime.getRuntime();

  maxMemory =
    runtime.maxMemory();

  usedMemory =
    runtime.totalMemory() -
    runtime.freeMemory();

  availableMemoryPercentage =
    1 -
    (double) usedMemory /
    maxMemory;

  if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {

    try {
      Thread.sleep(DELAY_TIME);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    waitForGarbageCollector(
      callback);
  } else {

    // Memory resources are availavle, go to next operation:

    callback.run();
  }
}

ASUS NEXUS 7 (2013) 32GIG: getMemoryClass () = 192 MAXMEMORY () = 201326592

لقد ارتكبت خطأً في النماذج الأولية لعبتي على Nexus 7 ، ثم اكتشفت أنها نفدت على الفور تقريبًا على جهاز الكمبيوتر اللوحي 4.04 لزوجتي (MemoryClass 48 ، Maxmemory 50331648)

سأحتاج إلى إعادة هيكلة مشروعي لتحميل عدد أقل من الموارد عندما أحدد أن MemoryClass منخفضة.
هل هناك طريقة في جافا لرؤية حجم الكومة الحالي؟ (أستطيع أن أراها بوضوح في logcat عند تصحيح الأخطاء ، لكنني أود أن أراها في الكود للتكيف ، مثل IF CurrentHeap> (maxmemory/2) تفريغ نقامات الصورة النقطية عالية الجودة ذات الجودة المنخفضة

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

Runtime rt = Runtime.getRuntime();
rt.maxMemory()

القيمة ب

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

القيمة هي MB

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