mam jakiś prosty kod Java, który napisałem do sztucznie używać dużo pamięci RAM i uważam, że kiedy się przynależne czasy, kiedy użyć tych znaczników:Dlaczego ograniczenie GC do 1 wątku zwiększa wydajność?
1029.59 seconds .... -Xmx8g -Xms256m
696.44 seconds ..... -XX:ParallelGCThreads=1 -Xmx8g -Xms256m
247.27 seconds ..... -XX:ParallelGCThreads=1 -XX:+UseConcMarkSweepGC -Xmx8g -Xms256m
Teraz rozumiem dlaczego -XX:+UseConcMarkSweepGC
zwiększa wydajność, ale dlaczego dostaję przyspieszenie, gdy ograniczę się do pojedynczego GC? Czy jest to artefakt mojego źle napisanego kodu java, czy też jest to coś, co można by zastosować również do poprawnie zoptymalizowanej javy?
Oto mój kod:
import java.io.*;
class xdriver {
static int N = 100;
static double pi = 3.141592653589793;
static double one = 1.0;
static double two = 2.0;
public static void main(String[] args) {
//System.out.println("Program has started successfully\n");
if(args.length == 1) {
// assume that args[0] is an integer
N = Integer.parseInt(args[0]);
}
// maybe we can get user input later on this ...
int nr = N;
int nt = N;
int np = 2*N;
double dr = 1.0/(double)(nr-1);
double dt = pi/(double)(nt-1);
double dp = (two*pi)/(double)(np-1);
System.out.format("nn --> %d\n", nr*nt*np);
if(nr*nt*np < 0) {
System.out.format("ERROR: nr*nt*np = %d(long) which is %d(int)\n", (long)((long)nr*(long)nt*(long)np), nr*nt*np);
System.exit(1);
}
// inserted to artificially blow up RAM
double[][] dels = new double [nr*nt*np][3];
double[] rs = new double[nr];
double[] ts = new double[nt];
double[] ps = new double[np];
for(int ir = 0; ir < nr; ir++) {
rs[ir] = dr*(double)(ir);
}
for(int it = 0; it < nt; it++) {
ts[it] = dt*(double)(it);
}
for(int ip = 0; ip < np; ip++) {
ps[ip] = dp*(double)(ip);
}
double C = (4.0/3.0)*pi;
C = one/C;
double fint = 0.0;
int ii = 0;
for(int ir = 0; ir < nr; ir++) {
double r = rs[ir];
double r2dr = r*r*dr;
for(int it = 0; it < nt; it++) {
double t = ts[it];
double sint = Math.sin(t);
for(int ip = 0; ip < np; ip++) {
fint += C*r2dr*sint*dt*dp;
dels[ii][0] = dr;
dels[ii][1] = dt;
dels[ii][2] = dp;
}
}
}
System.out.format("N ........ %d\n", N);
System.out.format("fint ..... %15.10f\n", fint);
System.out.format("err ...... %15.10f\n", Math.abs(1.0-fint));
}
}
Wątki mają narzut. Jeśli kod jest napisany w taki sposób, że nie będzie korzystał z dodatkowych wątków, dodanie wątków spowolni go. Gdybym miał zgadywać, powiedziałbym, że podanie GC więcej wątków powoduje, że zajmuje on więcej cykli zegara procesora, pozostawiając mniej dla rzeczywistego programu.To, czy jest to dobre, czy też nie, zależy całkowicie od charakteru wykonywanego programu i konkretnych kompromisów dotyczących prędkości/pamięci, które próbujesz osiągnąć. –
GC jest z natury problemem jednowątkowym. Wiele wątków powoduje dużo więcej narzutów: musi istnieć duży wykres obiektowy i duża ilość pamięci do odzyskania przed dodaniem wątków poprawia wydajność, ponieważ najpierw trzeba przezwyciężyć obciążenie. –
Dla prawdziwego testu porównawczego nie wystarczy uruchomić kod tylko raz w głównej metodzie. Bez fazy rozgrzewania i niektórych iteracji, aby uzyskać średnią wartość i wariancję, wartości są bez znaczenia. – isnot2bad