까다로운 경우에도 Java에서 가비지 수집을 강제 할 수 있습니까? 내가 알고 System.gc();
하고 Runtime.gc();
있지만, 그들은 단지 GC를 수행하는 것이 좋습니다. GC를 어떻게 강제 할 수 있습니까?
까다로운 경우에도 Java에서 가비지 수집을 강제 할 수 있습니까? 내가 알고 System.gc();
하고 Runtime.gc();
있지만, 그들은 단지 GC를 수행하는 것이 좋습니다. GC를 어떻게 강제 할 수 있습니까?
답변:
가장 좋은 방법은 System.gc()
가비지 수집기에서 수집하려는 힌트를 간단히 호출 하는 것입니다. 가비지 수집기는 비 결정적이므로 강제 로 즉시 수집 할 수있는 방법이 없습니다 .
non-deterministic == trouble
GC.Collect()
이 수집하지 않습니다. 자바 gc()
에서는 그렇지 않습니다.
jlibs 라이브러리는 가비지 컬렉션에 대한 좋은 유틸리티 클래스가 있습니다 . WeakReference 객체 로 멋진 작은 트릭을 사용하여 가비지 수집을 강제 할 수 있습니다 .
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
로모그래퍼 ReferenceQueue
하지만 여전히 정리하기 전에, 다음은 종결 후 통지를받을 것입니다. 마지막으로,이 개체의 메모리가 회수되었음을 성공적으로 감지하더라도 HotSpot과 같은 세대 GC에서는 여전히 거의 의미가 없습니다. 일반적으로 그것은 젊은 세대의 정리와 일치합니다.
System.gc(); System.gc();
그보다 더 잘 작동하는지 아는 것이 흥미로울 것입니다. 실제로, 몇 번만 호출 System.gc()
하면 충분합니다. 2에 도달 할 수있는 기회는 상당히 적습니다.
은 Using 자바 (Java ™) 가상 공작 기계 인터페이스 (JVM TI)를 함수
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
"VM이 가비지 수집을 수행하도록합니다." JVM TI는 Java 플랫폼 디버거 아키텍처 (JPDA)의 일부 입니다.
예 , 거의 같은 순서로 메소드를 호출해야하며 동시에이 메소드는 다음과 같습니다.
System.gc ();
System.runFinalization ();
이 두 메소드의 사용을 동시에 청소하는 하나의 오브젝트 일지라도 가비지 콜렉터 finalise()
는 도달 할 수없는 오브젝트 의 메소드 를 사용하여 지정된 메모리를 해제하고 finalize()
메소드 상태를 수행합니다.
그러나 가비지 수집기를 사용하면 메모리보다 최악의 소프트웨어에 과부하가 발생할 수 있기 때문에 가비지 수집기를 사용하는 것이 끔찍한 관행이지만 가비지 수집기는 자체 스레드를 가지고 있기 때문에 제어 할 수 없습니다. gc가 사용하는 알고리즘은 더 많은 시간이 걸리고 매우 비효율적 인 것으로 간주됩니다. gc의 도움으로 소프트웨어가 최악인지 확인해야합니다. 확실히 파산되었으므로 좋은 해결책은 gc에 의존해서는 안됩니다.
참고 : 이것은 finalize 메소드에서 객체를 재할 당하지 않는 경우에만 작동합니다.이 경우 객체가 살아 있으면 기술적으로 가능한 부활을 갖게됩니다.
gc()
가비지 수집을 실행하는 힌트 일뿐입니다. runFinalizers()
"버려진 것으로 확인 된"개체에서만 종료자를 실행합니다. gc가 실제로 실행되지 않았다면 그러한 객체가 없을 수도 있습니다.
OutOfMemoryError에 대한 문서에 따르면 VM이 전체 가비지 수집 후 메모리를 회수하지 않으면 발생하지 않는다고 선언합니다. 따라서 오류가 발생할 때까지 메모리 할당을 계속하면 이미 전체 가비지 수집을 수행했을 것입니다.
아마 당신이 정말로 묻고 싶은 질문은 "가비지 수집으로 회수해야한다고 생각하는 기억을 어떻게 되 찾을 수 있을까?"였습니다.
System.gc ()가 아닌 GC를 수동으로 요청하려면 다음을 수행하십시오.
.gc는 향후 릴리스에서 제거 할 후보입니다. Sun 엔지니어는 한 번은 전 세계에서 20 명 미만이 실제로 .gc ()를 사용하는 방법을 알고 있다고 언급했습니다. SecureRandom이 생성 한 데이터를 사용하는 데이터 구조, 약 4 만 개가 넘는 개체에서 vm은 포인터가 부족한 것처럼 속도가 느려집니다. 분명히 그것은 16 비트 포인터 테이블을 질식 시켰고 고전적인 "실패한 기계"동작을 보여 주었다.
나는 -Xms 등을 시도하여 약 57, xxx 개의 무언가가 나올 때까지 비트를 돌리고 있었다. 그런 다음 gc () 이후에 57,127에서 57,128 사이의 gc를 실행합니다-캠프이지 머니 (Easy Money)의 코드 팽창 속도에 대해.
설계에는 근본적인 재 작업, 아마도 슬라이딩 윈도우 접근 방식이 필요합니다.
명령 행에서 GC를 트리거 할 수 있습니다. 배치 / 크론 탭에 유용합니다.
jdk1.7.0/bin/jcmd <pid> GC.run
보다 :
JVM 사양은 가비지 수집과 관련하여 아무 것도 말하지 않습니다. 이로 인해 공급 업체는 GC를 자유롭게 구현할 수 있습니다.
따라서이 모호함은 가비지 콜렉션 동작에 불확실성을 유발합니다. 가비지 수집 방법 / 알고리즘에 대해 알고 싶다면 JVM 세부 정보를 확인해야합니다. 또한 동작을 사용자 정의하는 옵션도 있습니다.
가비지 수집이 필요한 이유를 설명하면 더 좋습니다. SWT를 사용하는 경우 메모리 Image
와 같은 자원을 제거 하고 Font
메모리 를 비울 수 있습니다 . 예를 들어 :
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
처리되지 않은 리소스를 결정하는 도구도 있습니다.
메모리가 부족하고 점점 더 많은 것을 얻는 OutOfMemoryException
다면 java -Xms128m -Xmx512m
그냥 대신 프로그램을 시작하여 java가 사용할 수있는 힙 공간을 늘려보십시오 java
. 그러면 초기 힙 크기는 128Mb이고 최대 512Mb이며 표준 32Mb / 128Mb보다 훨씬 큽니다.
java -Xms512M -Xmx1024M
다른 옵션은 새 객체를 만들지 않는 것입니다.
객체 풀링Java에서 GC의 필요성을 줄이기 위해 이 사라졌습니다.
오브젝트 풀링은 일반적으로 오브젝트 작성 (가벼운 오브젝트의 경우)보다 빠르지 않지만 가비지 콜렉션보다 빠릅니다. 10,000 개의 객체를 만들고 각 객체가 16 바이트 인 경우 GC가 회수해야하는 160,000 바이트입니다. 반면에 동시에 10,000 개가 모두 필요하지 않은 경우 새 개체를 만들 필요가없고 오래된 개체를 GC 할 필요가없는 개체를 재활용 / 재사용 할 풀을 만들 수 있습니다.
이와 같은 것 (평가되지 않음). 스레드 안전을 원할 경우 ConcurrentLinkedQueue에 대한 LinkedList를 교체 할 수 있습니다.
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
G1 GC가 포함 된 OracleJDK 10에서 단일 호출로 System.gc()
GC가 이전 콜렉션을 정리합니다. GC가 즉시 실행되는지 확실하지 않습니다. 그러나 GC는 System.gc()
루프에서 여러 번 호출 되더라도 Young Collection을 정리하지 않습니다 . GC가 Young Collection을 정리하게하려면 new byte[1024]
을 호출하지 않고 루프 (예 :)로 할당해야합니다 System.gc()
. System.gc()
어떤 이유로 전화 하면 GC가 Young Collection을 정리하지 못합니다.
정말로, 나는 당신을 얻지 못합니다. 그러나 "무한 객체 생성"에 대해 명확하게 말하면 큰 시스템에는 메모리에서 처리하고 살아있는 객체를 생성하는 일부 코드가 있다는 것을 의미했습니다. 실제로이 코드를 얻을 수는 없었습니다.
이것은 올바른 제스처입니다. 여러 포스터에서 이미 제공 한 표준 답변이 거의 있습니다. 이것을 하나씩 보자.
맞습니다. 실제 jvm은 없습니다. 그냥 사양입니다. 원하는 동작을 설명하는 많은 컴퓨터 과학입니다 ... 나는 최근에 네이티브 코드에서 Java 객체를 초기화하는 것을 파헤 쳤습니다. 원하는 것을 얻으려면 유일한 방법은 적극적인 nulling을하는 것입니다. 잘못하면 실수가 너무 나빠서 질문의 원래 범위로 제한해야합니다.
여기에있는 대부분의 포스터는 인터페이스 작업을하고 있다고 가정 할 것입니다. 그러한 경우에는 한 번에 전체 객체 또는 한 항목을 건네 주는지 확인해야합니다.
더 이상 객체가 필요하지 않은 경우 객체에 null을 할당 할 수 있지만 잘못된 경우 null 포인터 예외가 생성됩니다. NIO를 사용하면 더 나은 작업을 수행 할 수 있습니다.
당신이나 나 또는 다른 사람이 얻을 때마다 : " 그 끔찍하게 필요합니다. "그것은 당신이 작업하려는 것을 거의 완전히 파괴하는 거의 보편적 인 선구자입니다 .... 작은 샘플 코드를 작성하십시오. 실제 코드를 사용하여 질문을 보여주십시오.
좌절하지 마십시오. 종종 이것이 해결되는 것은 dba가 어딘가에서 구입 한 패키지를 사용하고 있으며 원래의 디자인이 대규모 데이터 구조에 맞게 조정되지 않았기 때문입니다.
매우 흔합니다.
참고로
System.runFinalizersOnExit (true) 메소드 호출은 Java가 종료되기 전에 종료 자 메소드가 호출되도록합니다. 그러나이 방법은 본질적으로 안전하지 않으며 더 이상 사용되지 않습니다. 대안은 Runtime.addShutdownHook 메소드를 사용하여“종료 훅”을 추가하는 것입니다.
마사 라트 시드 디키
가비지 수집기를 강제하는 간접적 인 방법이 있습니다. 가비지 콜렉터가 실행될 때까지 임시 오브젝트로 힙을 채우면됩니다. 가비지 컬렉터를 이런 식으로 강제하는 클래스를 만들었습니다.
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
용법:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
나는 그것이 지속적으로 힙을 채우는 때문에이 방법이 유용 얼마나 모르겠지만, 당신은 미션 크리티컬 한 응용 프로그램이있는 경우 반드시 GC를 강제을 -이 GC를 강제로 자바 이식 방법이 될 수 있습니다 때.
여기에 몇 가지를 추가하고 싶습니다. Java가 실제 머신이 아닌 가상 머신에서 실행되지 않도록하십시오. 가상 머신에는 머신과의 고유 한 통신 방법이 있습니다. 시스템마다 다를 수 있습니다. 이제 GC를 호출 할 때 Java 가상 머신이 가비지 콜렉터를 호출하도록 요청합니다.
가비지 콜렉터는 가상 머신과 함께 있으므로 강제로 정리를 수행 할 수 없습니다. 대신 가비지 콜렉터로 요청을 큐에 넣습니다. 특정 시간이 지나면 가상 머신에 따라 다릅니다 (일반적으로 JVM에 할당 된 임계 값 메모리가 가득 찬 경우 시스템에서 시스템으로 변경 될 수 있음) 실제 머신은 공간을 비 웁니다. :디
다음 코드는 assertGC (...) 메소드에서 가져온 것입니다. 비 결정적 가비지 수집기가 강제로 수집하려고합니다.
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
출처 (명확성을 위해 의견을 추가했습니다) : NbTestCase 예제