سؤال

لقد علقت في وقت سابق هذا السؤال ("لماذا java.lang.object ليست مجردة؟") تفيد أنني سمعت أن باستخدام أ byte[0] لأن القفل كان أكثر كفاءة بقليل من استخدام java.lang.Object. أنا متأكد من أنني قرأت هذا في مكان ما ولكن لا يمكنني تذكر أين: هل يعرف أي شخص ما إذا كان هذا صحيحًا بالفعل؟

أظن أن ذلك يرجع إلى تثبيت byte[0] تتطلب رمز بايت أقل قليلاً من Object, ، على الرغم من أنه تم الإشارة إلى ذلك byte[0] يتطلب تخزين إضافي من أجل تخزين حقل الطول ، لذلك يبدو أن هذا قد ينفي أي فائدة.

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

المحلول

حصلت على فضول بما يكفي لاختباره. مصدر الرمز:

public class Test {
    public static Object returnObject() {
        return new Object();
    }

    public static byte[] returnArray(){
        return new byte[0];
    }
}

Bytecode:

public static java.lang.Object returnObject();
  Code:
   0:   new     #2; //class java/lang/Object
   3:   dup
   4:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   7:   areturn

public static byte[] returnArray();
  Code:
   0:   iconst_0
   1:   newarray byte
   3:   areturn

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

نصائح أخرى

باستخدام java.lang.instrument.instrumentation للتحقق من الأحجام:
يستخدم الكائن 8 بايت ، يحتاج البايت [0] إلى 16 بايت. (لست متأكدًا مما إذا كان الحجم في بايت ، غير موثق).

حصلت أيضًا على الوقت لإنشاء كائن وبايت [0] (2 مرات): الكائن هو الفائز.

(يتم تشغيل جميع الاختبارات على جهاز كمبيوتر محمول Dell ، Intel 2Ghz ، Windos XP)

باستخدام client VM

java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Client VM (build 14.2-b01, mixed mode)

an implementation-specific approximation of the amount of storage
Object  = 8
byte[0] = 16

time to create 1000000000 instances
Object:  elapsed=11,140   cpu=9,766    user=9,703    [seconds]
byte[0]: elapsed=18,248   cpu=15,672   user=15,594   [seconds]

time to create 1000000000 instances
Object:  elapsed=11,135   cpu=9,828    user=9,750    [seconds]
byte[0]: elapsed=18,271   cpu=15,547   user=15,469   [seconds]

باستخدام server VM

java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Server VM (build 14.2-b01, mixed mode)

an implementation-specific approximation of the amount of storage
Object  = 8
byte[0] = 16

time to create 1000000000 instances
Object:  elapsed=8,441    cpu=7,156    user=7,125    [seconds]
byte[0]: elapsed=11,237   cpu=8,609    user=8,500    [seconds]

time to create 1000000000 instances
Object:  elapsed=8,501    cpu=7,234    user=7,156    [seconds]
byte[0]: elapsed=11,023   cpu=8,688    user=8,641    [seconds]

سأبقى مع new Object(), ليس فقط بسبب قابلية القراءة :-)

الرمز

public class ObjectArrayCompare {

  private static Object o;

  public static void main(String[] args) {
    Instrumentation instr = InstrumentationAgent.getInstrumentation();
    if (instr == null) {
        System.err.println("No Instrumentation, use \"-javaagent:Instrumentation.jar\"");
        return;
    }
    System.out.println();
    System.out.println("an implementation-specific approximation of the amount of storage");
    System.out.println("Object  = " + instr.getObjectSize(new Object()));
    System.out.println("byte[0] = " + instr.getObjectSize(new byte[0]));
    System.out.println();

    final int MAX = (int) 1.0e9;
    Timer timer;
    Times times;

    for (int j = 0; j < 2; j++) {
      System.out.println("time to create " + MAX + " instances"); 
      timer = new Timer();
      for (int i = 0; i < MAX; i++) {
        o = new Object();
      }
      times = timer.times();
      System.out.println("Object:  " + times);

      timer = new Timer();
      for (int i = 0; i < MAX; i++) {
        o = new byte[0];
      }
      times = timer.times();
      System.out.println("byte[0]: " + times);

      System.out.println();
    }
  }
}

مؤقت* الاستخدامات ThreadMXBean للحصول على الأوقات.

* المؤقت هو الفصل الذي صنعته من أجل التوقيت ، إنه كذلك ليس واحد من جافا مؤقت.

بحسب المواصفات لغة جافا, ، "جميع أنواع الفئة والمصفوفات ترث طرق كائن الفئة" ، لذلك لا أعرف كيف يمكن أن يكون البايت [0] أكثر كفاءة.

يبدو أن هذا صحيح بالنسبة ل الطبعة الأولى من المواصفات كذلك: "تعتبر الفئة الفائقة لنوع الصفيف كائنًا".

من المرجح أن يؤدي استخدام صفيف إلى إرباك القارئ IMHO.

يعد إنشاء كائنات أقل أكثر كفاءة من إنشاء المزيد ، لذلك إذا قامت بإنشاء كائنات كافية من الأهمية ، فأنت تقوم بإنشاء الكثير.

نمط استخدام صفيف فارغ في Java ككائن قفل ليس له علاقة بالأداء.

صفائف فارغة (حتى new Object[0]) هي الأفضل لأنها قابلة للتسلسل. باستخدام new Object() أنت تتخلى عن التسلسل التلقائي.

اعتدت على القيام (لا تهتم أبدًا بالأداء):

private final Object lock = new Object[0];

تستغرق المصفوفات البدائية أقل من رمز bytecode لإنشاء ، لذلك ربما new byte[0] سيكون أفضل".

يرى: هل من المقبول جعل القفل عابرًا لفئة قابلة للتسلسل؟

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

يمكنك أيضًا مقارنة النفقات العامة لاستخدام الأقفال الجوهرية لاستخدامها java.util.concurrent.locks.ReentrantLock صراحة أو واحدة تكتب نفسك على قمة AbstractQueuedSynchronizer. ما إذا كنت تستطيع تحمل إشارة إضافية إلى كائن مخصص بشكل منفصل يتطلب مزيدًا من التفاصيل حول مشكلتك للتقييم ، ولكن بالنظر إلى أنك تفكر بالفعل byte المصفوفات ، يجب أن تفكر في استخدام قفل جوهري متميز عن this المرجعي.

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