System.gc ()는 언제 뭔가를합니까?


118

Java에서 가비지 수집이 자동화된다는 것을 알고 있습니다. 그러나 System.gc()코드를 호출 하면 JVM이 해당 시점에서 가비지 수집을 수행할지 여부를 결정할 수 있음을 이해 했습니다. 이것이 정확히 어떻게 작동합니까? JVM은 정확히 어떤 기준 / 매개 변수에서 GC를 수행할지 여부를 결정 System.gc()합니까?

이것을 코드에 넣는 것이 좋은 경우에 대한 예가 있습니까?


4
개념이 너무 복잡해서 여기에 자세히 설명 할 수 없지만이 기사는 도움이 될 것입니다. chaoticjava.com/posts/how-does-garbage-collection-work
GEOCHET

정확한 동작은 JVM에 달려 있습니다. 즉, 구현에 따라 다릅니다.
Thorbjørn Ravn Andersen 2012-07-25

답변:


59

실제로는 일반적으로 가비지 콜렉션을 수행하기로 결정합니다. 대답은 실행중인 JVM, 어떤 모드에 있는지, 사용중인 가비지 수집 알고리즘과 같은 많은 요인에 따라 다릅니다.

나는 당신의 코드에서 그것에 의존하지 않을 것입니다. JVM이 OutOfMemoryError를 발생시키려는 경우 System.gc () 호출은이를 중지하지 않습니다. 가비지 컬렉터가 극도로 진행되기 전에 가능한 한 많이 해제하려고하기 때문입니다. 내가 실제로 사용하는 것을 본 유일한 시간은 사용자가 클릭 할 수있는 버튼에 연결된 IDE에 있지만 그다지 유용하지는 않습니다.


3
jconsole에서 가비지 수집을 강제 할 수 있습니다.
Benedikt Waldvogel

25
@bene 정말 "강제"할 수 있습니까? jconsole이 System.gc ()를 호출하고 있습니까?
John Meagher

4
System.gc()비디오 게임의 로딩 화면에서 사용 합니다. 그 시점에서 나는 전화가 가능한 모든 것을 제거했는지, 아니면 아무것도하지 않았는지 상관하지 않을 것이다. 그러나 나는 게임 플레이가 아닌 로딩 화면에서 "사용하지 않는 개체를 재활용하는 데 노력을 기울이는" 것을 선호 합니다.
Kröw

30

System.gc ()를 호출하는 것이 합리적이라고 생각할 수있는 유일한 예는 가능한 메모리 누수를 검색하기 위해 애플리케이션을 프로파일 링 할 때입니다. 프로파일 러는 메모리 스냅 샷을 찍기 직전에이 메서드를 호출한다고 생각합니다.


4
네, 저도 그렇게합니다. 예를 들어 Runtime.freeMemory ()에 의해 반환 된 값은 System.gc () 이후에만 실제로 의미가 있습니다. 일반적으로 수집 할 수없는 인스턴스에 의해 얼마나 많은 메모리가 차단되는지 알고 싶기 때문입니다. 물론 디버깅 / 메모리 프로파일 링에만 사용되며 프로덕션에서는 사용되지 않습니다.
sleske

아니, 다른 많은 시나리오에도 좋습니다. 예를 들어 수명주기를 인식하는 단일 패턴이 있다고 가정 해 보겠습니다. onStop ()에서 인스턴스를 null (ing)하는 경우 System.gc ()를 호출하여 도움을주는 것이 좋습니다.
Portfoliobuilder

26

Java 언어 사양은를 호출 할 때 JVM이 GC를 시작한다고 보장하지 않습니다 System.gc(). 이것이 "그 시점에서 GC를 수행하기로 결정할 수도 있고 결정하지 않을 수도 있습니다"의 이유입니다.

이제 Oracle JVM의 중추 인 OpenJDK 소스 코드 를 살펴보면에 대한 호출 System.gc()이 GC주기를 시작 한다는 것을 알 수 있습니다. J9와 같은 다른 JVM을 사용하는 경우 해당 문서를 확인하여 답을 찾아야합니다. 예를 들어 Azul의 JVM에는 지속적으로 실행되는 가비지 수집기가 있으므로에 대한 호출 System.gc()은 아무 작업도 수행하지 않습니다.

다른 답변은 JConsole 또는 VisualVM에서 GC 시작을 언급합니다. 기본적으로 이러한 도구는 System.gc().

일반적으로 코드에서 가비지 수집주기를 시작하고 싶지 않습니다. 애플리케이션의 의미 체계를 망칠 수 있기 때문입니다. 애플리케이션은 비즈니스 작업을 수행하고 JVM은 메모리 관리를 처리합니다. 이러한 문제를 분리해야합니다 (애플리케이션이 메모리 관리를 수행하도록하지 말고 비즈니스에 집중).

그러나에 대한 호출을 System.gc()이해할 수있는 경우는 거의 없습니다 . 예를 들어 마이크로 벤치 마크를 고려하십시오. 아무도 마이크로 벤치 마크 중간에 GC주기가 발생하기를 원하지 않습니다. 따라서 각 측정 사이에 GC주기를 트리거하여 모든 측정이 빈 힙으로 시작되도록 할 수 있습니다.


26

Java에서 GC를 제어 할 수 없습니다. VM이 결정합니다. 나는 사례를 통해 실행 적이 System.gc()있다 필요합니다 . 때문에 System.gc()호출이 단순히 VM은 가비지 수집을 할 것을 제안하고 또한 전체 가비지 컬렉션 (다중 세대 힙에 이전 및 새 세대)를 수행 한 후 실제로 발생할 수 있습니다 더 많은 CPU 사이클이 필요 이상으로 소비 될 수 있습니다.

어떤 경우에는 애플리케이션이 무거운 작업이 발생하기 전에 다음 몇 분 동안 유휴 상태가 될 것임을 알 수 있으므로 VM이 지금 전체 수집을 수행하도록 제안하는 것이 합리적 일 수 있습니다. 예를 들어, 응용 프로그램을 시작하는 동안 많은 임시 개체를 초기화 한 직후 (즉, TON의 정보를 캐시했으며 1 분 정도는 많은 활동을하지 않을 것임을 알고 있습니다). Eclipse 시작과 같은 IDE를 생각해보십시오. 초기화에 많은 작업을 수행하므로 아마도 초기화 직후에 전체 gc를 수행하는 것이 좋습니다.


17

전화 할 경우 매우 조심해야합니다 System.gc(). 이를 호출하면 애플리케이션에 불필요한 성능 문제가 추가 될 수 있으며 실제로 수집을 수행한다고 보장 할 수 없습니다. 실제로 System.gc()java 인수를 통해 명시 적을 비활성화 할 수 있습니다 -XX:+DisableExplicitGC.

가비지 컬렉션에 대한 자세한 내용은 Java HotSpot Garbage Collection 에서 제공하는 문서를 읽어 보는 것이 좋습니다 .


내 안드로이드 응용 프로그램에서 항상 OutOfMemoryException이 발생합니다. 그래서 나는 원치 않는 모든 참조와 객체를 지우기 위해 내 클래스의 onDestroy 함수에서 System.gc ()를 사용할 생각이었습니다. 좋은 접근 방식입니까
Sagar Devanga 2015 년

2
@Sagar Devanga 설명하는대로 gc를 수동으로 호출하는 것은 도움이되지 않을 것입니다. OOM을 던지기 전에, JVM은 이미 메모리 확보하기 위해 수집 위해 쓰레기를 시도합니다
Scrubbie

10

System.gc()VM에 의해 구현되며 구현에 따라 다릅니다. 예를 들어 구현자는 단순히 반환하고 아무것도 할 수 없습니다.

수동 수집을 발행해야하는 경우에 대해 이렇게 할 수있는 유일한 시간은 소규모 컬렉션 ( Map<String,<LinkedList>> 예 : 예를 들어)이 포함 된 대규모 컬렉션을 포기 하고 성능 히트를 시도하고 싶을 때입니다. 하지만 대부분의 경우 걱정할 필요가 없습니다. GC는 대부분의 경우 슬프게도 당신보다 잘 알고 있습니다.


8

직접 메모리 버퍼를 사용하는 경우 직접 메모리가 부족하더라도 JVM이 GC를 실행하지 않습니다.

전화를 걸고 ByteBuffer.allocateDirect()OutOfMemoryError가 발생하면 GC를 수동으로 트리거 한 후이 호출이 괜찮다는 것을 알 수 있습니다.


System.gc ()가 직접 할당을 수집하는 반면 JVM은 일반적으로 (OOM을 던지기 전에) 수집하지 않는다고 말하는 것입니까? 나는 그것이 틀렸다고 생각하기 때문입니다. 명시 적 GC 후에 할당이 성공할 수있는 유일한 이유는 추가 시간과 종료자가 해제 된 힙 내 개체의 가능성 (및 일부 직접 할당 된 개체 해제) 때문입니다.
eckes

최신 버전의 Java 6에서 allocateBuffer의 코드는 OutOfMemoryError를 발생시키기 전에 항상 System.gc ()를 실행합니다. 최종화 코드에는 Cleaners직접 메모리가 사용하는 지름길이 있습니다. 즉, 너무 느릴 수 있으므로 종료 자 스레드에 의해 해제되지 않습니다. 그렇더라도 직접 메모리 영역을 특히 빠르게 생성하는 경우 OOME을 얻을 수 있습니다. 해결책은 그렇게하지 않고 가능한 한 직접 메모리 영역을 재사용하는 것입니다.
Peter Lawrey 2012

1
고마워, 이것은 내 경험처럼 들린다. 그래서 대답은 이전 Java 버전에서만 정확하다고 생각합니다.
eckes

5

대부분의 JVM은 GC를 시작합니다 (-XX : DiableExplicitGC 및 -XX : + ExplicitGCInvokesConcurrent 스위치에 따라 다름). 그러나 나중에 더 나은 구현을 허용하기 위해 사양이 잘 정의되어 있지 않습니다.

사양에 설명이 필요합니다. 버그 # 6668279 : (spec) System.gc ()는 사용을 권장하지 않으며 동작을 보장하지 않음을 나타내야합니다.

내부적으로 gc 메소드는 RMI 및 NIO에서 사용되며 동기 실행이 필요합니다. 이는 현재 논의 중입니다.

버그 # 5025281 : System.gc ()가 동시 (stop-the-world 아님) 전체 수집을 트리거하도록 허용


3

Garbage CollectionJava데스크톱 / 노트북 / 서버에서 자바로 코딩 된 소프트웨어를 실행하는 경우 에서 좋습니다 . System.gc()또는 Runtime.getRuntime().gc()으로 전화 할 수 있습니다 Java.

이러한 호출 중 어떤 것도 아무 작업도 수행하지 않는다는 점에 유의하십시오. 이는 jvm이 가비지 콜렉터를 실행하기위한 제안 일뿐입니다. GC를 실행하는지 여부는 JVM이 결정합니다. 그래서 짧은 대답 : 우리는 그것이 언제 실행되는지 모릅니다. 더 긴 대답 : JVM은 시간이 있으면 gc를 실행합니다.

Android에도 동일하게 적용됩니다. 그러나 이로 인해 시스템 속도가 느려질 수 있습니다.


JVM은 시간이 있으면 gc를 실행합니다 . 항상 사실은 아닙니다. Jvm은 Eden 메모리가 가득 차면 gc를 실행할 수 있습니다.
abdelmouheimen

2

일반적으로 VM은 OutOfMemoryException을 발생시키기 전에 자동으로 가비지 수집을 수행하므로 명시 적 호출을 추가해도 성능 저하가 이전 시점으로 이동한다는 점을 제외하고는 도움이되지 않습니다.

그러나 관련성이있을 수있는 경우를 만난 것 같습니다. 아직 효과가 있는지 테스트하지 않았기 때문에 확실하지 않습니다.

파일을 메모리 매핑 할 때 충분한 메모리 블록을 사용할 수 없을 때 map () 호출이 IOException을 던진다 고 생각합니다. map () 파일 바로 앞에 가비지 컬렉션이 도움이 될 수 있다고 생각합니다. 어떻게 생각해?


2

우리는 절대 가비지 수집을 강제 할 수 없습니다. System.gc는 가비지 수집을 위해 vm만을 제안하지만 실제로 메커니즘이 실행되는 시간은 아무도 모릅니다. 이것은 JSR 사양에 명시된 바와 같습니다.


2

다양한 가비지 컬렉션 설정을 테스트하는 데 시간을 할애하는 데에는 많은 말이 있지만 위에서 언급했듯이 일반적으로 그렇게하는 것은 유용하지 않습니다.

저는 현재 메모리가 제한된 환경과 상대적으로 많은 양의 데이터를 포함하는 프로젝트를 진행하고 있습니다. 내 환경을 한계까지 밀어 붙이는 큰 데이터가 몇 개 있으며 메모리 사용량을 줄일 수 있었음에도 불구하고 이론적으로는 잘 작동해야하지만 여전히 힙 공간 오류가 발생합니다. 자세한 GC 옵션은 가비지 수집을 시도했지만 아무 소용이 없음을 보여주었습니다. 디버거에서 System.gc ()를 수행 할 수 있고 "많은"메모리를 사용할 수있을 것입니다. 여분이 많지는 않지만 충분합니다.

결과적으로 내 응용 프로그램이 System.gc ()를 호출하는 유일한 시간은 데이터 처리에 필요한 큰 버퍼가 할당되는 코드 세그먼트에 들어 가려고 할 때이며 사용 가능한 메모리에 대한 테스트는 내가 그렇지 않다는 것을 나타냅니다. 그것을 보장합니다. 특히, 처리중인 데이터가 최소 100-200MB 인 경우를 제외하고는 정적 데이터가 최소 300MB를 차지하는 1GB 환경을 살펴보고 있습니다. 소스. 이는 모두 자동 데이터 변환 프로세스의 일부이므로 데이터는 모두 장기적으로 비교적 짧은 기간 동안 존재합니다.

안타깝게도 가비지 수집기를 조정하는 다양한 옵션에 대한 정보를 사용할 수 있지만 대부분 실험적인 프로세스로 보이며 이러한 특정 상황을 처리하는 방법을 이해하는 데 필요한 하위 수준의 세부 사항을 쉽게 얻을 수 없습니다.

내가 System.gc ()를 사용하고 있음에도 불구하고, 나는 여전히 명령 줄 매개 변수를 사용하여 조정을 계속했고, 극복 할 수 없었음에도 불구하고 내 애플리케이션의 전체 처리 시간을 상대적으로 상당히 향상시킬 수 있었다. 더 큰 데이터 블록으로 작업함으로써 발생하는 걸림돌. 즉, System.gc ()는 도구입니다 .... 매우 신뢰할 수없는 도구입니다. 사용 방법에주의를 기울이지 않으면 자주 작동하지 않는 것이 좋습니다.



0

명시적인 GC를 실행하는 것이 좋을 때 구체적인 예를 생각할 수 없습니다.

일반적으로 명시 적 GC를 실행하면 실제로는 좋은 것보다 더 많은 해를 끼칠 수 있습니다. 명시 적 GC는 모든 객체를 통과 할 때 훨씬 더 오래 걸리는 전체 컬렉션을 트리거하기 때문입니다. 이 명시 적 gc가 반복적으로 호출되면 전체 GC를 실행하는 데 많은 시간이 소요되므로 애플리케이션 속도가 느려질 수 있습니다.

또는 힙 분석기로 힙을 살펴보고 라이브러리 구성 요소가 명시 적 GC를 호출하는 것으로 의심되는 경우 JVM 매개 변수에 gc = -XX : + DisableExplicitGC를 추가하여 해제 할 수 있습니다.


2
우리는 System.gc ()를 호출하여 닫히지 않은 MappedByteBuffer 객체를 닫으려고합니다. 따라서 객체에 대해 'close ()'를 호출하더라도 다른 프로세스 나 파일 자르기에 사용할 수 없습니다. 불행히도 여전히 항상 닫히는 것은 아닙니다.
Tim Cooper

0

브루스 에켈 (Bruce Eckel), 명시 적으로 하나의 유스 케이스에 의해 자바의 생각에 Accroding 으로 System.gc () 당신이 즉, 호출, 힘 마무리로 할 때 호출 것은 마무리 하는 방법.


주의 : 종료를 강제하는 방법이 있습니다. (문제는 실제로
종료자를

-1

system.gc가 작동하는 동안 모든 응답이 중지되어 가비지 수집기가 모든 객체를 스캔하여 삭제해야하는지 확인할 수 있습니다. 응용 프로그램이 웹 프로젝트 인 경우 gc가 완료 될 때까지 모든 요청이 중지되고 이로 인해 웹 프로젝트가 monent에서 작동하지 않을 수 있습니다.

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