Kto wywołuje System.gc() ?

Każdy, kto miał do czynienia z aplikacjami Javy których rozmiar sterty liczy się w gigabajtach wie, że jedną z rzeczy których należy unikać jak ognia jest tzw. odśmiecanie pełne (Full GC). W większości przypadków można to osiągnąć przez rozważny wybór algorytmu GC i staranne dobranie jego parametrów. Nie rozwiązuje to jednak przypadku, gdy cykl pełnego odśmiecania wyzwalany jest przez jawne wywołanie System.gc() co manifestuje się wpisami w logach procesu odśmiecania zaczynających się od Full GC (System) (HotSpot) lub <sys> (IBM J9).
W przypadku maszyny wirtualnej IBM (IBM J9) w celu wykrycia miejsc skąd pochodzą te wywołania wystarczy dodać odpowiednią opcję do parametrów uruchomieniowych maszyny wirtualnej

-Xtrace:print=mt,methods={java/lang/System.gc},trigger=method{java/lang/System.gc,jstacktrace}

W przypadku maszyny Oracle HotSpot sprawa jest nieco trudniejsza. Początkowo planowałem wykorzystać instrumentalizację przez BCEL ale w końcu zdecydowałem się na wykorzystanie BTrace. W tym celu napisałem prosty próbnik

import com.sun.btrace.annotations.*; 
import static com.sun.btrace.BTraceUtils.*; 
@BTrace class SystemGcCalls {    
	@OnMethod(clazz="java.lang.System", method="gc")    
	public void printStack() {
		Threads.jstack();
		println("");    
	} 
}

i zainstalowałem go dla testu w działającej instalacji Eclipse (o które wiedziałem, że Full GC jest wywoływane bez potrzeby co wyłączyłem, świadom konsekwencji, za pomocą opcji -XX:+DisableExplicitGC).

$ ./btrace <pid> /Users/Jarek/Code/BTrace/SystemGcCalls.java

Wkrótce moim oczom ukazały się stosy wywołań

java.lang.System.gc(System.java)
org.eclipse.ui.internal.ide.application.IDEIdleHelper$3.run(IDEIdleHelper.java:181)
org.eclipse.core.internal.jobs.Worker.run(Worker.java:53)

Okazuje się, że klasa org.eclipse.ui.internal.ide.application.IDEIdleHelper próbuje wykrywać, kiedy IDE jest bezczynne i wywołuje wtedy System.gc(). Po prostu cudownie! Analizując kod klasy IDEIdleHelper okazuje się, że można doprowadzić do tego, że System.gc() nie będzie wywołane przez IDE ustawiając parametr „ide.gc” w eclipse.ini

-Dide.gc=false

Dalsza analiza wskazuje na błędy dotyczące tego zachowania zgłoszone do Eclipse Bugzilla: Bug 118335 i Bug 136855. Jest to kolejny przykład na to, że zakładanie że wie się lepiej od JVM kiedy przeprowadzić odśmiecanie rzadko prowadzi do czegokolwiek dobrego.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s