Java에서 메모리를 비우는 방법?


146

C와 비슷한 Java로 메모리를 비울 수있는 방법이 있습니까? free() 기능 있습니까? 아니면 객체를 null로 설정하고 GC에만 의존하는 옵션입니까?


151
알았어 ... 한 가지만 해보자. 무언가가 나쁜 습관이라고 생각하고 격려하는 것이 아니라고해서 투표에 합당하지는 않습니다. 가비지 수집에 의존하지 않고 Java에서 메모리를 해제 할 수있는 방법이 있는지 묻는 분명하고 유효한 질문입니다. 실망스럽고 일반적으로 유용하지 않거나 좋은 아이디어는 아니지만 Felix가 아는 것을 알지 못하면 시나리오가 필요하지 않다는 것을 알 수 없습니다. 펠릭스는 그것을 사용하지 않을 수도 있습니다. 그는 가능한지 알고 싶을 수도 있습니다. 결코 투표를받을 자격이 없습니다.
Daniel Bingham

7
명확히하기 위해, 그것은 이전의 의견이 아니라 반드시 이것을 표명 한 사람을 목표로합니다.
Daniel Bingham

답변:


96

Java는 관리 메모리를 사용하므로 메모리를 할당 할 수있는 유일한 방법은 new 연산자 것 뿐이며 메모리 할당을 해제 할 수있는 유일한 방법은 가비지 수집기를 사용하는 것입니다.

메모리 관리 백서 (PDF)는 진행 상황을 설명하는 데 도움이 될 수 있습니다.

전화 할 수도 있습니다 System.gc()가비지 수집기가 즉시 실행되도록 제안하기 위해 를 . 그러나 Java 런타임은 코드가 아닌 최종 결정을 내립니다.

에 따르면 Java 문서 ,

gc 메소드를 호출하면 Java Virtual Machine이 현재 사용중인 메모리를 빠르게 재사용 할 수 있도록 사용하지 않는 객체를 재활용하는 데 노력을 기울이게됩니다. 메소드 호출에서 제어가 리턴되면, JVM (Java Virtual Machine)은 모든 버려진 오브젝트에서 공간을 확보하기 위해 최선을 다했습니다.


5
가비지 콜렉터가 강제로 실행됩니다. 그래도 메모리를 확보하도록 강제하지는 않습니다.
Pablo Santa Cruz

13
Pablo는 없습니다. GC를 강제로 실행하지 않습니다.
Jesper

1
믿을만한 사람이 모든 HotSpotVM의 가비지 수집기를 System.gc()완전히 무시한다고 들었 습니다.
Esko

1
winXp에서 java SE GC는 모든 System.gc () 또는 거의 모든 것을 실행하지만 API 문서는이를 보장하지 않습니다.
teodozjan

2
@Pablo Santa Cruz 메모리가 확보되지 않는다는 것은 무엇을 의미합니까? 방금 누출이 발생한 것으로 보이며 램 사용량이 안정화 된 것처럼 프로그램에서 테스트했습니다. 다니엘은 방금 제안한 방법에 따라 매번 사용 된 램의 비율이 항상 어떻게 안정화되는지를 제안했습니다. 당신은 사람들이 나를 혼란스럽게합니다.

65

아무도 객체 참조를 명시 적으로 설정하는 것에 대해 언급하지 않은 것 같습니다. null . 이는 여러분이 고려하고 싶은 메모리를 "비우는"합법적 인 기술입니다.

예를 들어, List<String>크기가 매우 커지는 메소드의 시작 부분에 a를 선언 했지만 메소드 중간 쯤까지만 필요하다고 가정 해보십시오. 이 시점에서 목록 참조를null 메소드가 완료되기 전에 가비지 수집기가이 객체를 잠재적으로 회수 할 수있게합니다 (그리고 참조는 범위를 벗어남).

실제로이 기술은 거의 사용하지 않지만 매우 큰 데이터 구조를 처리 할 때는 고려해 볼 가치가 있습니다.


8
실제로 메소드의 일부에만 사용되는 객체에 대해 많은 작업을 수행하는 경우 제안합니다. 분석법이 너무 복잡하거나 분석법을 전후 부분으로 나누거나 코드의 첫 번째 절반에 블록을 사용하십시오 (나중에 테스트 스크립트에 더 유용함)
Peter Lawrey

5
객체 참조를 null로 설정하는 것이 중요한 곳은 다른 오래 지속되는 객체 (또는 정적 변수)에서 참조 할 때입니다. 예를 들어, 오래 지속되는 큰 객체 배열이 있고 그 객체 중 하나를 사용하지 않으면 GC에 객체를 사용할 수 있도록 배열 참조를 null로 설정해야합니다.
핫 릭

22
System.gc(); 

가비지 수집기를 실행합니다.

GC의 메소드를 호출하면 제안 메모리를 만들 수 있도록 사용하지 않은 객체의 재활용을 자바 가상 머신의 소비 노력들이 현재 빠른 다시 사용할 차지합니다. 메소드 호출에서 제어가 리턴되면, JVM (Java Virtual Machine)은 모든 버려진 오브젝트에서 공간을 확보하기 위해 최선을 다했습니다.

권장하지 않습니다.

편집 : 2009 년에 원래의 답변을 썼습니다. 이제 2015 년입니다.

가비지 수집기는 Java가 사용 된 ~ 20 년 동안 꾸준히 향상되었습니다. 이 시점에서 가비지 수집기를 수동으로 호출하는 경우 다른 방법을 고려할 수 있습니다.

  • 제한된 수의 컴퓨터에서 GC를 강제 실행하는 경우로드 밸런서 지점을 멀리 두는 것이 좋습니다 경우 현재 머신에서 연결된 클라이언트에 대한 서비스가 완료 될 때까지 기다렸다가 연결을 끊기 위해 일정 시간이 지난 후 제한 시간이 초과 될 수 있습니다. -JVM을 다시 시작하십시오. 이것은 끔찍한 해결책이지만 System.gc ()를보고있는 경우 강제 레스토랑이 가능한 스톱 갭이 될 수 있습니다.
  • 다른 가비지 수집기를 사용하십시오. 예를 들어, G6 수집기 (지난 6 년간 새로 도입 된)는 일시 중지가 적은 모델입니다. 전반적으로 더 많은 CPU를 사용하지만 실행을 강제로 멈추지 않는 것이 가장 좋습니다. 서버 CPU는 이제 거의 모든 코어가 여러 개이기 때문에 이것이 실제로 사용할 수있는 절충점입니다.
  • 메모리 사용 튜닝 플래그를보십시오. 특히 최신 버전의 Java에서 장기 실행 객체가 많지 않은 경우 힙에서 newgen 크기를 늘리십시오. newgen (young)은 새로운 객체가 할당되는 곳입니다. 웹 서버의 경우 요청을 위해 생성 된 모든 것이 여기에 배치 되며이 공간이 너무 작 으면 Java는 객체를 수명이 더 긴 메모리로 업그레이드하는 데 더 많은 시간을 소비하여 죽이는 데 비용이 많이 듭니다. (newgen이 너무 작 으면 비용을 지불하게됩니다.) 예를 들어 G1에서 :
    • XX : G1NewSizePercent (기본값은 5, 아마도 중요하지 않습니다.)
    • XX : G1MaxNewSizePercent (기본값은 60입니다. 아마도이 값을 올리십시오.)
  • 더 이상 일시 정지해도 가비지 수집기에 문제가 없다고 알려주십시오. 이로 인해 시스템이 나머지 제약 조건을 유지할 수 있도록 GC가 더 자주 실행됩니다. G1에서 :
    • XX : MaxGCPauseMillis (기본값 : 200)

1
내 게시물에 댓글을 달면 종종 아무것도하지 않으며 반복적으로 호출하면 JVM이 불안정 해지고 그렇지 않을 수 있습니다. 또한 개를 뛰어 넘을 수도 있습니다. 조심스럽게 접근하십시오.
Dean J

1
"gc 메소드 호출은 JVM 확장 노력을 제안합니다"의 "제안"부분을 강조합니다.
matt b

2
@Jesper, Dean의 답변에는 "제안"이 나와 있습니다. 실제로 그는 메소드의 javadocs에서 정확한 문서를 게시했습니다.
matt b

2
@Software Monkey : 예, 방금 편집했을 수 있습니다. 그러나 Dean J가 분명히 활동적 이었기 때문에 (몇 분 전 게시), 나는 그에게 요청하는 것이 예의라고 생각했다. 그가하지 않았다면 여기로 돌아와서 편집하고 내 의견을 삭제했을 것입니다.
Daniel Pryden

1
또한 왜 권장하지 않는지 말할 가치가 있습니다. JVM이 GC를 실행하기위한 "제안"에주의를 기울이면 거의 확실하게 앱 실행 속도가 느려질 것입니다!
Stephen C

11

* "나는 개인적으로 미래의 적절한 삭제를 위해 자리 표시 자로 nulling 변수를 사용합니다. 예를 들어, 실제로 배열 자체를 삭제 (null 만들기)하기 전에 배열의 모든 요소를 ​​무효화하는 데 시간이 걸립니다."

이것은 불필요합니다. Java GC가 작동하는 방식은 객체를 참조하지 않는 객체를 찾는 것입니다. 따라서 참조가있는 Object x (= variable) a가 있으면 GC가 삭제하지 않습니다. 그 객체에 :

a -> x

이보다 null이 null 인 경우 :

a -> null
     x

이제 x는 참조를 가리 키지 않고 삭제됩니다. a가 x와 다른 객체를 참조하도록 설정했을 때도 마찬가지입니다.

따라서 객체 x, y 및 z를 참조하는 배열 arr과 배열을 참조하는 변수 a가 있으면 다음과 같습니다.

a -> arr -> x
         -> y
         -> z

이보다 null이 null 인 경우 :

a -> null
     arr -> x
         -> y
         -> z

따라서 GC는 arr에 참조가 설정되지 않은 것으로 확인하고 삭제하여 다음 구조를 제공합니다.

a -> null
     x
     y
     z

이제 GC는 x, y 및 z를 찾아서 삭제합니다. 배열의 각 참조를 무효화하면 아무것도 개선되지 않고 코드의 CPU 시간과 공간 만 사용됩니다 (즉, 그 이상으로 아프지 않을 것입니다. ).


5

모든 프로그램에서 메모리를 확보하려는 유효한 이유 (java 또는 not)는 운영 체제 레벨의 다른 프로그램에서 더 많은 메모리를 사용할 수 있도록하기위한 것입니다. 내 Java 응용 프로그램이 250MB를 사용하는 경우 강제로 1MB로 줄이고 249MB를 다른 응용 프로그램에서 사용할 수 있도록 할 수 있습니다.


Java 프로그램에서 249MB의 청크를 명시 적으로 비워야하는 경우 메모리 관리가 내가 먼저하고 싶은 것이 아닙니다.
Marc DiMillo

3
그러나 Java 힙 내에서 스토리지를 비우더라도 (일반적인 경우) 다른 앱에서 스토리지를 사용할 수있는 것은 아닙니다.
핫 릭

5

Yiannis Xanthopoulos와 Hot Licks의 답변과 의견을 확장하기 위해 (죄송하지만 아직 의견을 말할 수 없습니다!)이 예제와 같은 VM 옵션을 설정할 수 있습니다.

-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30

jdk 7에서는 VM이 ​​유휴 상태 일 때 GC 후에 힙의 30 % 이상이 사용 가능 해지면 사용되지 않은 VM 메모리를 해제합니다. 이러한 매개 변수를 조정해야합니다.

아래 링크에서 강조 표시되지는 않았지만 일부 가비지 수집기는 이러한 매개 변수를 따르지 않을 수 있으며 기본적으로 java가 둘 이상인 경우 (위의 UseG1GC 인수) ).

VM 인수

업데이트 : java 1.8.0_73의 경우 JVM이 때때로 기본 설정으로 소량을 릴리스하는 것을 보았습니다. 힙의 ~ 70 %가 사용되지 않은 경우에만 수행되는 것으로 보입니다. OS에 실제 메모리가 부족한 경우 더 적극적으로 릴리스되는지 알 수 없습니다.


4

나는 이것에 대해 실험을 해왔다.

System.gc();가비지 콜렉터 실행 만 제안하는 것은 사실입니다 .

그러나 System.gc();모든 참조를로 설정 한 후 호출 null하면 성능 및 메모리 점유가 향상됩니다.


"System.gc ()를 호출하면 모든 참조를 null로 설정 한 후 성능과 메모리 점유가 향상된다"고 확신 할 수 없습니다. System.gc ()의 계산 복잡성이 엄청 나기 때문입니다. 그리고 System.gc ()를 호출하고 실제로 가비지를 수집 한 후에도 jvm은 OS 또는 시스템에 메모리를 다시 제공하지 않을 수 있습니다. JVM은 나중에 참조 할 수 있도록 메모리를 보유 할 수 있습니다. 이 답변을 참조하십시오 .
Md. Abu Nafee Ibna Zahid

3

실제로 메모리 블록을 할당하고 해제하려면 직접 ByteBuffer를 사용하십시오. 메모리를 비울 수없는 이식 가능한 방법도 있습니다.

그러나 제안한 바와 같이 C에서 메모리를 비워야한다고해서 반드시 그렇게해야하는 것은 아닙니다.

정말로 free ()에 대한 유스 케이스가 있다고 생각되면 질문에 포함 시켜서 우리가 무엇을 해야하는지 볼 수 있다면 더 좋은 방법이있을 것입니다.


3

javacoffeebreak.com/faq/faq0012.html 에서 완전히

우선 순위가 낮은 스레드는 사용자를 위해 가비지 수집을 자동으로 처리합니다. 유휴 시간 동안 스레드가 호출 될 수 있으며 Java에서 객체에 이전에 할당 된 메모리를 해제 할 수 있습니다. 그러나 걱정하지 마십시오. 개체가 삭제되지 않습니다!

객체에 대한 참조가 없으면 가비지 수집기의 게임이됩니다. C ++에서 free와 같은 일부 루틴을 호출하는 대신 객체에 대한 모든 참조를 null에 할당하거나 참조에 새 클래스를 할당하면됩니다.

예 :

public static void main(String args[])
{
  // Instantiate a large memory using class
  MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192);

  // Do some work
  for ( .............. )
  {
      // Do some processing on myClass
  }

  // Clear reference to myClass
  myClass = null;

  // Continue processing, safe in the knowledge
  // that the garbage collector will reclaim myClass
}

코드가 많은 양의 메모리를 요청하려는 경우 가비지 수집기에서 우선 순위가 낮은 스레드로 공간을 허용하지 않고 공간 회수를 시작하도록 요청할 수 있습니다. 이렇게하려면 코드에 다음을 추가하십시오.

System.gc();

가비지 수집기는 사용 가능한 공간을 확보하려고 시도하며 가능한 한 많은 메모리를 회수하여 응용 프로그램을 계속 실행할 수 있습니다 (메모리 조각화 문제는 특정 플랫폼에 적용될 수 있음).


1

필자의 경우 Java 코드는 가까운 장래에 다른 언어 (주로 C ++)로 이식 될 예정이므로 적어도 립 서비스를 사용하여 메모리를 적절하게 해제하여 나중에 이식 프로세스에 도움이되도록하고 싶습니다.

나는 개인적으로 미래의 적절한 삭제를 위해 자리 표시 자로 nulling 변수에 의존합니다. 예를 들어, 실제로 배열 자체를 삭제 (null 만들기)하기 전에 배열의 모든 요소를 ​​무효화하는 데 시간이 걸립니다.

그러나 제 사건은 매우 구체적이며,이 작업을 수행 할 때 성능이 저하된다는 것을 알고 있습니다.


1

* "예를 들어, 크기가 매우 커지는 메소드의 시작 부분에서 List를 선언했지만 메소드를 반쯤 진행할 때까지만 필요하다고 가정하십시오.이 시점에서 List 참조를 널로 설정할 수 있습니다 메소드가 완료되기 전에 가비지 콜렉터가이 오브젝트를 잠재적으로 회수 할 수있게합니다 (그리고 어쨌든 참조는 범위를 벗어남). " *

이것은 맞지만이 솔루션은 일반화 할 수 없습니다. List 객체 참조를 null로 설정하는 동안 가비지 수집에 메모리를 사용할 수 있지만 이것은 기본 유형의 List 객체에만 적용됩니다. List 객체에 참조 유형이 포함 된 경우 List 객체 = null을 설정하면 목록에 포함 된 참조 유형 중 어느 것도 역 참조되지 않습니다. 이 경우 List object = null을 설정하면 가비지 수집 알고리즘이 개체가 분리 된 것으로 판단하기에 충분하지 않으면 가비지 수집에 사용할 수없는 개체의 포함 된 참조 유형이 고아가됩니다.


1
이것은 사실이 아닙니다. Java 가비지 수집기는이를 올바르게 처리 할 수있을 정도로 똑똑합니다. List를 null로 지정하면 (그리고 List 내의 개체에 다른 참조가없는 경우) GC는 List 내의 모든 개체를 회수 할 수 있습니다. 현재로서는 그렇게하지 않을 수도 있지만 결국에는이를 되 찾을 것입니다. 순환 참조도 마찬가지입니다. 기본적으로 GC가 작동하는 방식은 orphraned 객체를 찾은 다음 다시 찾는 것입니다. 이것이 GC의 모든 일입니다. 당신이 그것을 묘사하는 방식은 GC를 전혀 쓸모 없게 만듭니다.
Dakkaron

1

이미 자바는 자동 가비지 수집을 제공하기 때문에 때로는 객체의 크기와 남은 양을 알고 싶을 것입니다. import java.lang;Runtime r=Runtime.getRuntime(); 사용 메모리의 값을 얻기 위해 mem1=r.freeMemory();메모리를 호출에 r.gc();방법과 전화를freeMemory()


1

JAVA의 권장 사항은 null에 할당하는 것입니다

에서 https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html

더 이상 필요하지 않은 변수에 널값을 명시 적으로 지정하면 가비지 콜렉터가 안전하게 회수 할 수있는 메모리 부분을 식별 할 수 있습니다. Java는 메모리 관리를 제공하지만 메모리 누수 나 과도한 메모리 사용을 방지하지는 않습니다.

응용 프로그램은 객체 참조를 해제하지 않아 메모리 누수를 유발할 수 있습니다. 그렇게하면 Java 가비지 콜렉터가 해당 오브젝트를 회수하지 못하므로 사용되는 메모리 양이 증가합니다. 사용 후 변수에 대한 참조를 명시 적으로 무효화하면 가비지 수집기가 메모리를 회수 할 수 있습니다.

메모리 누수를 감지하는 한 가지 방법은 프로파일 링 도구를 사용하고 각 트랜잭션 후에 메모리 스냅 샷을 만드는 것입니다. 정상 상태의 누수없는 응용 프로그램은 가비지 수집 후 안정적인 활성 힙 메모리를 표시합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.