Какой способ объявления переменной является самым быстрым? - PullRequest
2 голосов
/ 28 мая 2010

Для переменной, используемой в функции, которая вызывается очень часто, и для реализации в J2ME на ежевике (если это что-то изменило, вы можете объяснить)?

class X {
    int i;
    public void someFunc(int j) {
        i = 0;
        while( i < j ){
            [...]
            i++;
        }
    }
}

или

class X {
    static int i;
    public void someFunc(int j) {
        i = 0;
        while( i < j ){
            [...]
            i++;
        }
    }
}

или

class X {
    public void someFunc(int j) {
        int i = 0;
        while( i < j ){
            [...]
            i++;
        }
    }
}

Я знаю, что есть разница, как осуществляется доступ к статической и нестатической переменной класса, но я не знаю, что это повлияет на скорость. Я также помню, как читал где-то, что внутри-функциональные переменные могут быть доступны быстрее, но я не знаю, почему и где я это прочитал.

Справочная информация по вопросу: некоторые функции рисования в играх вызываются слишком часто, и даже небольшая разница во времени доступа может повлиять на общую производительность, когда переменная используется в большом цикле.

Обновление

Я установил небольшой тест (код ниже) и запустил его на реальном устройстве, чтобы посмотреть, на что похожи результаты. Я выполнил 10000 вызовов функции, которая зациклилась 10000 раз, обращаясь к переменной.

  • если переменная была в рабочем состоянии, для запуска
  • если переменная принадлежала классу, для запуска * 1023 потребовалось ~ 21700 мс *
  • , если переменная принадлежала классу, но была статической, для ее запуска требовалось ~ 210000 мс.

Я не знаю, насколько уместны результаты теста, будут ли они соответствовать реальной программе и нет ли другого внешнего фактора в игре. Но, если они это делают, так как это соответствует наиболее часто используемому представлению здесь, тогда есть существенная разница между временем доступа.

Подпадает ли это под преждевременную оптимизацию? Возможно, но это также кажется полезным руководством для максимально возможного использования внутрифункционных переменных. Даже копирование переменной класса во встроенную функцию может повлиять на время выполнения.

   final static int MAX = 10000;
   private void runTest()
   {
       long startTime = System.currentTimeMillis();
       for(int count = 0; count < MAX; count++)
           test1(MAX);
       test1.setText(""+(System.currentTimeMillis()-startTime));

       startTime = System.currentTimeMillis();
       for(int count = 0; count < MAX; count++)
           test2(MAX);
       test2.setText(""+(System.currentTimeMillis()-startTime));

       startTime = System.currentTimeMillis();
       for(int count = 0; count < MAX; count++)
           test3(MAX);
       test3.setText(""+(System.currentTimeMillis()-startTime));

   }

   void test1(int j)
   {
       int i = 0;
       while(i < j)
       {
           i++;
       }
   }
   int i2;
   void test2(int j)
   {
       i2 = 0;
       while(i2 < j)
       {
           i2++;
       }
   }
   static int i3;
   void test3(int j)
   {
       i3 = 0;
       while(i3 < j)
       {
           i3++;
       }
   }

Ответы [ 6 ]

8 голосов
/ 28 мая 2010

Они имеют совершенно другую семантику - хотите ли вы, чтобы значение было частью состояния класса, частью состояния экземпляров класса или локальным для метода?

У JIT больше возможностей для оптимизации последней версии, поскольку он знает все о том, где может использоваться переменная (и ему не нужно беспокоиться о других потоках, обращающихся к ней). Я бы сказал, что вероятно будет самым быстрым.

Вы должны действительно протестировать - и вообще, сначала напишите наиболее читаемый код и посмотрите, действительно ли у вас есть узкое место, прежде чем пытаться проводить такую ​​микрооптимизацию.

3 голосов
/ 28 мая 2010

Вы должны тщательно профилировать код, прежде чем даже подумать об этом виде микрооптимизации. А затем внедрить и измерить эффекты любых возможных микрооптимизаций.

Слишком сложно предсказать, какая (если есть!) Из трех версий будет быстрее на вашей конкретной платформе.

2 голосов
/ 28 мая 2010

Лично я думаю, что вы не увидите заметной разницы между этими тремя. Почему бы просто не попробовать все три и запустить некоторые тесты производительности? Это единственный способ узнать наверняка, так как способ, которым JVM оптимизирует вещи под прикрытием, может быть не интуитивным.

Мне трудно поверить, что это ваше узкое место в производительности. Мой подход состоит в том, чтобы написать это наиболее логичным способом и искать оптимизацию в другом месте.

1 голос
/ 28 мая 2010

Я тоже помню, что где-то читал внутри функции переменные могут быть доступны быстрее, но я не знаю почему

Локальные переменные могут храниться в регистре, самой быстрой памяти, которая существует. Если у вас нет очень умного JIT, поля экземпляра и класса должны находиться в основной памяти (или в кэше), поскольку они могут быть видны другим потокам.

Поскольку это также лучшее решение с точки зрения чистоты кода, вам обязательно следует использовать локальную переменную.

0 голосов
/ 28 мая 2010

Если ваша целевая платформа не имеет очень нечетной реализации JVM, порядок производительности:

  • локальная переменная
  • элемент static / объекта

Причина, по которой локальные переменные обеспечивают лучшую производительность, заключается в том, что они:

  • JVM специально поддерживает более короткие байт-коды
  • Никакой дополнительной информации для доступа к ним не требуется (элементы объекта должны быть адресованы с помощью ссылки this, а статическим членам нужна ссылка на класс)
  • Видны только локальному потоку, и поэтому JIT может выполнять для них различные оптимизации (например, помещать их в регистр).

Также следует отметить, что параметры метода обрабатываются так же, как локальные переменные на уровне байт-кода.

0 голосов
/ 28 мая 2010

Или вы можете просто использовать традиционный цикл for, который восстанавливает эту память, как только цикл заканчивается:

class X {
    public void someFunc(int j) {
        for(int i = 0; i < j; i++){
            [...]
        }
    }
}
...