Tentei optimize (memória) meu programa, mas GC ainda está tornando-lag

Raghav:

Eu escrevi um pedaço de software em Java que verifica se proxies estão trabalhando, enviando uma solicitação HTTP usando o proxy.

Demora cerca de 30.000 proxies a partir de um banco de dados, em seguida, tenta verificar se eles estão operacionais. Os proxies recebidos do banco de dados utilizado para ser retornado como um ArrayList<String>, mas foram alterados para Deque<String>por motivos enunciados a seguir.

A forma como o programa funciona é que há um ProxyRequestobjeto que armazena o IP e porta como uma String e int respectivamente. O ProxyRequestobjeto tem um método isWorkingProxy()que tenta enviar um pedido usando um proxy e retorna um booleansobre se ele foi bem sucedido.

Este ProxyRequestobjeto é enrolado em torno de um RunnableProxyRequestobjeto que chama super.isWorkingProxy()na overrided run()método. Com base na resposta do super.isWorkingProxy(), o RunnableProxyRequestobjeto atualiza um banco de dados MySQL.

Note que a atualização do banco de dados MySQL é synchronized().

Ele roda em 750 tópicos usando um FixedThreadPool (em um VPS), mas no final, torna-se muito lento (preso em ~ 50 threads), o que obviamente implica o lixo coletor está funcionando. Este é o problema.

Eu tentei o seguinte para melhorar a lag, não parece ao trabalho:

1) Utilizando um Deque<String>proxies e usando Deque.pop()obter o Stringem que o proxy é. Este (eu acredito), faz continuamente o Deque<String>menor, o que deve melhorar atraso causado pela GC.

2) Coloque o con.setConnectTimeout(this.timeout);, onde this.timeout = 5000;Desta forma, a conexão deve retornar um resultado em 5 segundos. Se não, o fio está concluído e já não deve estar ativo no pool de threads.

Além disso, eu não conheço nenhuma outra maneira que eu posso melhorar o desempenho.

Alguém pode recomendar uma maneira para mim para melhorar o desempenho para evitar / stop ficando para o final dos tópicos de GC? Eu sei que há uma questão Stackoverflow sobre este ( encadeamentos Java abrandar no final do processamento ), mas eu já tentou de tudo na resposta e não tem funcionado para mim.

Obrigado pelo seu tempo.

Partes de codigo:

Laço adicionando tópicos à FixedThreadPool:

//This code is executed recursively (at the end, main(args) is called again)
//Create the threadpool for requests
//Threads is an argument that is set to 750.
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(threads);
Deque<String> proxies = DB.getProxiesToCheck();

while(proxies.isEmpty() == false) {
    try {
        String[] split = proxies.pop().split(":");

        Runnable[] checks = new Runnable[] {
            //HTTP check
            new RunnableProxyRequest(split[0], split[1], Proxy.Type.HTTP, false),
            //SSL check
            new RunnableProxyRequest(split[0], split[1], Proxy.Type.HTTP, true),
            //SOCKS check
            new RunnableProxyRequest(split[0], split[1], Proxy.Type.SOCKS, false)
            //Add more checks to this list as time goes...
        };

        for(Runnable check : checks) {
            executor.submit(check);
        }

    } catch(IndexOutOfBoundsException e) {
        continue;
    }
}

ProxyRequest classe:

//Proxy details
private String proxyIp;
private int proxyPort;
private Proxy.Type testingType;

//Request details
private boolean useSsl;

public ProxyRequest(String proxyIp, String proxyPort, Proxy.Type testingType, boolean useSsl) {
    this.proxyIp = proxyIp;
    try {
        this.proxyPort = Integer.parseInt(proxyPort);
    } catch(NumberFormatException e) {
        this.proxyPort = -1;
    }
    this.testingType = testingType;
    this.useSsl = useSsl;
}

public boolean isWorkingProxy() {
    //Case of an invalid proxy
    if(proxyPort == -1) {
        return false;
    }

    HttpURLConnection con = null;

    //Perform checks on URL
    //IF any exception occurs here, the proxy is obviously bad.
    try {
        URL url = new URL(this.getTestingUrl());
        //Create proxy
        Proxy p = new Proxy(this.testingType, new InetSocketAddress(this.proxyIp, this.proxyPort));
        //No redirect
        HttpURLConnection.setFollowRedirects(false);
        //Open connection with proxy
        con = (HttpURLConnection)url.openConnection(p);
        //Set the request method
        con.setRequestMethod("GET");
        //Set max timeout for a request.
        con.setConnectTimeout(this.timeout);
    } catch(MalformedURLException e) {
        System.out.println("The testing URL is bad. Please fix this.");
        return false;
    } catch(Exception e) {
        return false;
    }

    try(
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            ) {

        String inputLine = null; StringBuilder response = new StringBuilder();
        while((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }

        //A valid proxy!
        return con.getResponseCode() > 0;

    } catch(Exception e) {
        return false;
    }
}

RunnableProxyRequest classe:

public class RunnableProxyRequest extends ProxyRequest implements Runnable {


    public RunnableProxyRequest(String proxyIp, String proxyPort, Proxy.Type testingType, boolean useSsl) {

        super(proxyIp, proxyPort, testingType, useSsl);

    }

    @Override
    public void run() {

        String test = super.getTest();

        if(super.isWorkingProxy()) {

            System.out.println("-- Working proxy: " + super.getProxy() + " | Test: " +  test);

            this.updateDB(true, test);

        } else {
            System.out.println("-- Not working: " + super.getProxy() + " | Test: " +  test);

            this.updateDB(false, test);
        }   


    }

    private void updateDB(boolean success, String testingType) {
        switch(testingType) {
            case "SSL":
                DB.updateSsl(super.getProxyIp(), super.getProxyPort(), success);
                break;
            case "HTTP":
                DB.updateHttp(super.getProxyIp(), super.getProxyPort(), success);
                break;
            case "SOCKS":
                DB.updateSocks(super.getProxyIp(), super.getProxyPort(), success);
                break;
            default:
                break;
        }
    }
}

DB classe:

//Locker for async 
private static Object locker = new Object();

private static void executeUpdateQuery(String query, String proxy, int port, boolean toSet) {
    synchronized(locker) {
        //Some prepared statements here.
    }
}
Raghav:

Graças a Peter Lawrey para me guiar para a solução! :)
Seu comentário:

@ILoveKali eu encontrei bibliotecas de rede não são suficientes agressivo em desligar uma ligação quando as coisas vão realmente errado. Tempos de espera tendem a funcionar melhor quando a conexão está bem. YMMV

Então eu fiz alguma pesquisa e descobri que eu tinha para também usar o método setReadTimeout(this.timeout);. Anteriormente, eu só estava usando setConnectTimeout(this.timeout);!

Graças a este post ( HttpURLConnection tempo limite defaults ) que explicou o seguinte:

Infelizmente, na minha experiência, parece usar esses padrões pode levar a um estado instável, dependendo do que acontece com a sua conexão com o servidor. Se você usar um HttpURLConnection e não explicitamente definido (pelo menos ler) tempos de espera, sua conexão pode entrar em um estado obsoleto permanente. Por padrão. Então, sempre definir setReadTimeout para "algo" ou você pode órfão conexões (e possivelmente fios Dependendo de como o aplicativo é executado).

Portanto, a resposta final é: O GC foi indo muito bem, não foi responsável pelo atraso. Os fios eram simplesmente preso para sempre em um único número, porque eu não definir o tempo limite de leitura, e assim o isWorkingProxy()método nunca obteve um resultado e continuei lendo.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=182129&siteId=1
Recomendado
Clasificación