Czy robi to różnicę, jeśli deklaruję zmienne wewnątrz lub na zewnątrz pętli w Javie? [Zamknięte]

13

Możliwa duplikat:
gdzie deklarujesz zmienne? Top metody lub kiedy jej potrzebujesz?

Czy robi to różnicę, jeśli deklaruję zmienne wewnątrz lub na zewnątrz pętli w Javie?

Czy to jest

for(int i = 0; i < 1000; i++) {
   int temp = doSomething();
   someMethod(temp);
}

równa się (w odniesieniu do użycia pamięci)?

int temp = 0;
for(int i = 0; i < 1000; i++) {
   temp = doSomething();
   someMethod(temp);
}

A jeśli zmienna tymczasowa jest na przykład ArrayList?

for(int i = 0; i < 1000; i++) {
   ArrayList<Integer> array = new ArrayList<Integer>();
   fillArray(array);
   // do something with the array
}

EDYCJA: z javap -cmam następujące wyjście

Zmienna poza pętlą:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iconst_0      
       3: istore_2      
       4: iload_2       
       5: sipush        1000
       8: if_icmpge     25
      11: invokestatic  #2                  // Method doSomething:()I
      14: istore_1      
      15: iload_1       
      16: invokestatic  #3                  // Method someMethod:(I)V
      19: iinc          2, 1
      22: goto          4
      25: return  

Zmienna wewnątrz pętli:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     23
       9: invokestatic  #2                  // Method doSomething:()I
      12: istore_2      
      13: iload_2       
      14: invokestatic  #3                  // Method someMethod:(I)V
      17: iinc          1, 1
      20: goto          2
      23: return        

A dla zainteresowanych ten kod:

public class Test3 {
    public static void main(String[] args) {
        for(int i = 0; i< 1000; i++) {
            someMethod(doSomething());
        }   
    }
    private static int doSomething() {
        return 1;
    }
    private static void someMethod(int temp) {
        temp++;
    }
}

produkuje to:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     21
       9: invokestatic  #2                  // Method doSomething:()I
      12: invokestatic  #3                  // Method someMethod:(I)V
      15: iinc          1, 1
      18: goto          2
      21: return   

Ale wtedy optymalizacja odbywa się w czasie wykonywania. Czy istnieje sposób spojrzenia na zoptymalizowany kod? (Przepraszam za długą EDYCJĘ)

Puckl
źródło
1
Cieszę się, że faktycznie spojrzałeś na demontaż i mam nadzieję, że nauczył cię czegoś. Miałem nadzieję, że ktoś z prawdziwym doświadczeniem w Javie odpowie na twoje ostatnie pytanie dotyczące zoptymalizowanego kodu, ale być może możesz opublikować tę konkretną część na Stackoverflow - wydaje się to bardzo konkretne pytanie.
Joris Timmermans
Tak, postaram się uzyskać zoptymalizowany kod. (Pytanie nieco się zmieniło, zadałem to pytanie ze zoptymalizowanym kodem w edycji)
Puckl,
Uszkodzony link na duplikacie. Czas uczynić to pytanie oryginalnym.
Strefa

Odpowiedzi:

4

Wspólna odpowiedź na większość tych pytań powinna brzmieć: „dlaczego nie spróbujesz i się nie dowiesz?”. W Javie prawdopodobnie mógłbyś rzucić okiem na wygenerowany bytecode (uważam, że narzędzie to nazywa się javap), aby zobaczyć, jaka jest różnica w kodzie bajtów między tymi dwoma sposobami deklarowania zmiennej.

Takie postępowanie jest lepszym doświadczeniem w nauce, ponieważ następnym razem, gdy napotkasz problem optymalizacji, możesz użyć tego samego narzędzia do sprawdzenia, czy kompilator działa zgodnie z oczekiwaniami - pomoże ci to uniknąć niepotrzebnej zmiany kodowania styl, gdy optymalizator radzi sobie sam, lub znajdowanie faktycznych poprawek, gdy naprawdę potrzebujesz ostatniej wydajności.

Joris Timmermans
źródło
3

Krótka odpowiedź: nie. Podobne pytania były już gdzieś na tej stronie. Nie ma zauważalnej różnicy w odniesieniu do wygenerowanego kodu bajtowego. Zadeklarowanie ich w razie potrzeby powoduje zmniejszenie liczby wierszy kodu

Oto zaakceptowana odpowiedź: /software//a/56590/43451

Kemoda
źródło
A co z wydajnością, gdy tworzysz nowy obiekt w pętli, który równie dobrze można utworzyć tylko raz?
Bubblewrap,
3
W tym przypadku oczywiście występuje utrata wydajności i pamięci. Ale nie jest tak w przypadku pytania
operacyjnego
1
Link jest zepsuty.
Zon
1

Na poziomie pojedynczej zmiennej nie ma znaczącej różnicy w wydajności, ale gdybyś miał funkcję z 1000 pętlami i 1000 zmiennymi (nie wspominając o złym stylu), mogą występować różnice systemowe, ponieważ całe życie wszystkich zmiennych byłoby to samo zamiast nakładających się. Może to wpływać na wielkość stosu i zdolność śmieciarza do czyszczenia zmiennych, które były utrzymywane przy życiu dłużej niż to konieczne.

Ponadto znacznie lepszym stylem jest nadawanie zmiennym możliwie najmniejszego zakresu. Zapobiega wypadkom.

ddyer
źródło
To nie jest prawda - na poziomie JVM nie ma czegoś takiego jak ograniczony zakres zmiennych lokalnych.
Michael Borgwardt,
czy masz na myśli to, że jeśli piszę dla (int i = ..) 1000 razy, na stosie będzie 1000 różnych zmiennych po wyjściu z funkcji?
ddyer
zgodnie z artima.com/insidejvm/ed2/jvm8.html „Na przykład, jeśli dwie zmienne lokalne mają ograniczone zakresy, które się nie nakładają, takie jak zmienne lokalne i i j w Przykładzie 3b, kompilatory mogą używać tej samej pozycji tablicy dla obu zmiennych. ”I to tylko ma sens, kompilatory mogą w ten sposób optymalizować rozmiar ramki stosu.
ddyer
1
Słuszna uwaga; ale jeśli mówimy o optymalizacjach kompilatora, kompilator może prawie równie łatwo ponownie wykorzystać wpisy zmiennych lokalnych dla zmiennych, które mają nakładający się zakres leksykalny, ale nie są używane w sposób nakładający się.
Michael Borgwardt,