2017-04-20 1 views
0

저는 현재 응용 프로그램을 최적화하고 있으며 거의 ​​1 기가의 RAM을 차지하는 것으로 나타났습니다. 나는 프로파일 링을하고 문제를 발견했다 :나는 내가 만든 텍스처 클래스에서 픽셀 데이터를 가지고있는 int 배열을 생성함으로써 많은 메모리를 할당하고 있었다. 그러나 이것은 새로운 배열을 만들 때 이전 배열이 더 이상 사용되지 않으며 어디에도 참조가 없으므로 혼란 스럽습니다.Java 참조되지 않은 배열이 여전히 메모리를 차지합니다.

나는이 문제를 재현 테스트 프로그램을 작성했습니다 :

public class Main { 

    static class ArrayHolder { 
     int[] array; 

     void init() { 
      array = null; 
      array = new int[4000]; 
     } 
    } 

    public static void main(String[] args) { 
     ArrayHolder holder = new ArrayHolder(); 
     for (int i = 0; i < 1000000; i++) { 
      holder.init(); 
     } 
     System.out.println(holder.array.length); 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

나는 프로그램이 RAM 600 메가 바이트까지 사용이 코드를 실행

. ArrayHolder에서 init() 메서드를 호출하면 배열 필드가 새 배열로 설정되고 이전 배열에 대한 참조가 손실되므로 그 이유를 알지 못합니다. 그것은 더 이상 공간을 차지하지 않는다는 것을 의미하지 않습니까? 이것이 멍청한 질문이라면 유감스럽게 생각합니다.하지만 왜이 사람이 내가 여기서 잘못하고 있는지 설명 할 수 있습니까?

+0

이전 배열은 gc의 재량에 의해서만 시작되었습니다. 메모리를 재 할당 한 직후에 gc가 실행되면 공간은 다시 확보되지 않을 것입니다. – SMA

+0

큰 배열은 tenured 공간에 추가되며 채워지는 경우 기본적으로 GC-ed됩니다. 예 : 잠자기해도 GC가 실행되지 않습니다. 간단히 말해서, 이렇게 많은 수의 큰 배열을 만드는 것은 여러 가지 이유로 이상적입니다. –

답변

1

array참조이고 Java의 배열입니다. 이 점에서 그들은 java.lang.Object에서 파생 된 다른 일반 객체와 같습니다. 배열에 대한 참조가 없으면 즉시 가비지 콜렉션이 수행 될 필요가 있습니다.

메모리를 해제 할 때 지연이 발생할 수 있습니다. 가비지 수집기는 필요할 때 불필요한 개체를 수집합니다.

가비지 컬렉터 이 실행 되더라도이 실행되는 경우에도 프로세스가 메모리를 다시 운영 체제로 넘길 것이라고 보증하지 않거나 OS가 해당 프로세스에서 메모리를 다시 가져옵니다.

+0

그 점을 지적 해 주셔서 감사합니다. 이 특정 예제의 메모리 사용을 줄이는 방법에 대해 어떻게 생각하십니까? 아니면 그냥 GC에 맡기시겠습니까? 왜냐하면 1 기가는 간단한 응용 프로그램에 비해 너무 비싸기 때문입니다. – RagingRabbit

+0

나는 단순히 GC를 신뢰할 것이다. 1GB는 내가 갖고있는 192GB 머신에 단순한 부담이 될 수 없으므로 1GB 스파이크로는 CPU가 사용 중이면 제 상자에 GC를 실행하기에 충분하지 않습니다. – Bathsheba

+0

JVisualVM을 사용하여 프로그램을 다시 실행했지만 가비지 수집을 수행했지만 메모리 사용량은 변함이 없습니다. GC가 수집하지 않기로 결정 했습니까, 아니면 문제입니까? – RagingRabbit

2

개체에 참조가 없기 때문에 메모리를 차지하지 않는다는 의미는 아닙니다. GC가 실행 되어야만 메모리에서 "제거"됩니다. 공간을 차지하는 참조가없는 객체를 메모리에 가질 수 있습니다. GC를 실행했는지, 명시 적으로 호출하지 않았는지 확인하십시오 (좋은 생각은 아닙니다). 또한, 당신이 실제로 당신의 객체에 대한 강한 참조를 가지고 있는지 발견 할 것을 제안합니다.

System.gc()을 사용하여 GC를 명시 적으로 호출합니다.

'-XX : + PrintGCDetails'와 같은 JVM 인수를 추가하여 GC가 실행되었는지 확인할 수 있습니다.

+0

가비지 수집기가 실행되었는지 여부와 어떻게 명시 적으로 호출 하는지를 확인하고 왜 그렇게하지 않아야합니까? – bleistift2

+0

@ bleistift2 - 내 답변을 편집하여 필요한 것을 추가하십시오. 왜 GC를 명시 적으로 호출하는 것이 좋지 않은지에 관해서는 http://stackoverflow.com/questions/66540/when-does-system-gc-do-anything – TheLostMind

+0

에 가보자. System.gc()는 권고이다. – Bathsheba

관련 문제