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Ę)


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.


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


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.


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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.