[RESOLVIDO] Web service REST não baixa memoria

Boa tarde Pessoal!
Criei um web service REST em servidor tomcat para fornecer dados para aplicativo Android.
O problema é a cada acesso ele sobe o consumo memória e não baixa mais.
Ja efetuei algumas otimizações que resolveram parte do problema. Mas ainda continuo com esse problema de consumo de memória que não baixa muito menos estabiliza.
Alguém já passou por isso?

Dê mais detalhes do que está usando e fazendo de funcionalidade para que ajude a quem possa te ajudar.

Hibernate por exemplo dependendo como estiver usando pode se tornar uma bomba. Debuga e tente ver o ponto exato que a memória começa a subir nas requisições seguintes, daí você especifica melhor a dúvida.

1 curtida

Bom dia javaflex! Vamos lá, estou usando o hibernate com as seguintes configurações:

<!-- CONFIGURACAO -->

            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.archive.autodetection" value="class" />


            <!-- POOL -->
             <property name="hibernate.c3p0.automaticTestTable" value="con_test"/>
            <property name="hibernate.c3p0.idleConnectionTestPeriod" value="60"/>
            <property name="hibernate.c3p0.initialPoolSize" value="0"/>
            <property name="hibernate.c3p0.maxIdleTime" value="60"/>
            <property name="hibernate.c3p0.maxPoolSize" value="15"/>
            <property name="hibernate.c3p0.minPoolSize" value="0"/>
            <property name="hibernate.c3p0.maxStatements" value="0"/>
            <property name="hibernate.c3p0.acquireIncrement" value="1"/><!--tempo entre uma tentativa e outra de conseguir adquirir uma conexao -->
            <property name="hibernate.c3p0.checkoutTimeout" value="50000"/><!-- tempo devida da conexao estando inativa -->
            
            <property name="hibernate.c3p0.maxStatementsPerConnection" value="10"/>
            <property name="hibernate.c3p0.acquireRetryDelay" value="1000"/>
            <property name="hibernate.c3p0.acquireRetryAttempts" value="5"/><!-- qtde de vezes que o c3p0 tentara abrir a conexao -->
            <property name="hibernate.c3p0.breakAfterAcquireFailure" value="true"/>
            <property name="hibernate.c3p0.maxIdleTimeExcessConnections" value="30"/>
            <property name="hibernate.c3p0.numHelperThreads" value="3"/>
            <property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces" value="false"/>
            <property name="hibernate.c3p0.unreturnedConnectionTimeout" value="0"/>    
            
            <property name="hibernate.c3p0.breakAfterAcquireFailure" value="true"/>    

Noto que a cada requisição ao WebService sobem muitas Threads C3P0PooledConnectionPoolMaager e ficam em Wait. Isso aparentemente ja me atrapalhou mais mas agora não tenho tanto problema, porém não sei se pode ser isso que esta dando problema em não baixar a memoria.

Meu AuthenticationFilter esta desta maneira:

@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter{
    
    protected static EntityManager getEntityManager() throws NamingException {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("xxxxxPU");
        return emf.createEntityManager();
    }

    private EntityManager em;
    
    @Override
    public void filter(ContainerRequestContext requestContext)
            throws IOException {

        String token = getHeaderToken(requestContext);
        Long userId = getUserIdBasedOnToken(token);
        setUserId(userId.toString(), requestContext);
    }

    private String getHeaderToken(ContainerRequestContext requestContext) {
        String authorizationHeader = requestContext
                .getHeaderString(HttpHeaders.AUTHORIZATION);

        if (authorizationHeader == null
                || !authorizationHeader.startsWith("XXXXX ")) {
            throw new NotAuthorizedException(
                    "Authorization header must be provided");
        }
        return authorizationHeader.substring("XXXXX".length()).trim();
    }

    private Long getUserIdBasedOnToken(String token)
            throws NotAuthorizedException{
        
        
        try {
            em = getEntityManager();
        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        em.getTransaction().begin();
        Query query = this.em.createQuery("SELECT l from login l where l.token = '" + token+"'");
        
        
        
        Login user = new Login();
        user = (Login) query.getSingleResult();
        
        em.getTransaction().commit();
        em.close();

        if ((user == null) || (user.getTokenExpire().before(new Date()))) {
            throw new NotAuthorizedException(
                    "Authorization token expired");
        }
        
        return user.getIdLogin();
    }

    private void setUserId(final String userId,
            ContainerRequestContext requestContext) {
        requestContext.setSecurityContext(new SecurityContext() {
            @Override
            public Principal getUserPrincipal() {
                return new Principal() {
                    @Override
                    public String getName() {
                        return userId;
                    }
                };
            }

            @Override
            public boolean isUserInRole(String role) {
                return true;
            }

            @Override
            public boolean isSecure() {
                return false;
            }

            @Override
            public String getAuthenticationScheme() {
                return null;
            }
        });
    }
}

Se é que me permite, o assunto aqui não é com a sua duvida, mas sim uma dica pelo que vi no seu código rs,

Fazer isso pode acarretar em problemas maiores

Query query = this.em.createQuery("SELECT l from login l where l.token = '" + token+"'");

Evite a sql injection

Abraços.

Você está criando uma fábrica de entitymanager a cada requisição, é isso mesmo?

Poxa verdade pkf66 e John-Jones, to fazendo besteira.
Ja corrigi a classe chamando a verificação em um DAO e efetuei testes mas ainda estou com problemas.

Experimenta usar JDBC puro sem vestígios de hibernate.

1 curtida

O que você espera conseguir com um DAO?

Eu perguntei se estava criando uma fábrica a cada requisição. Se não me engano isso é errado. Você precisa mudar o código para criar a factory apenas uma vez e reutilizar entre as requisições, não precisa usar DAO nenhum.

Se ele ainda não corrigiu isso, realmente é um ponto desastroso.

Muita atenção com o EntityManagerFactory, sua criação é custosa e pode afetar de forma significativa o desempenho da sua aplicação. Outra coisa, para sistemas de produção não é muito recomendado a própria aplicação gerenciar o datasource, recomendo passar essa tarefa para seu servidor de aplicação/container… você pode fazer isso facilmente com um arquivo xml dentre da sua aplicação onde vai indicar os parametros para o proprio tomcat gerenciar as conexões e consequentemente o pool de conexões.

Pessoal depois de umas duas semanas brigando com esse trem consegui resolver.
Estava trabalhando o EntityManager direto no resource do WebService de forma errada.
Testei varias formas de fazer as consultas e os inserts e nada.
Até que achei esse tutorial que deu certo!
http://www.devmedia.com.br/crud-completo-com-hibernate-e-jpa/32711
Criei um DAO conforme este exemplo e tudo ficou lindo.
Obrigado pelas dicas @javaflex e @pfk66 foram fundamentais para conseguir começar a achar o erro.