JPA queries memory leak?

198 Views Asked by At

We are profiling our application using Jprofiler to solve memory leaks and came across following observations:

We ran our application on the same data set to check and took multiple snapshots after marking Heap to see the Classes contributing to memory leak.

enter image description here

The byte[], String, int[] after checking their allocations all point to JPA queries. For example the allocation Hotspots for byte[] all point to query results :

QuerImpl.getSingleResult,

QueryImpl.getResultList

EnitiyManger.find :

enter image description here

Similar results were found for allocations of String, jav.util.HashMap$Node:

enter image description here

The one query on JPA which shows significant allocation is checkResourceID in Dao class:

@Stateless
@EJB(name = "java:global/ResourceProceduresDaoImpl", beanInterface = ResourceProceduresDao.class)
public class ResourceProceduresDaoImpl<R> implements ResourceProceduresDao<R> {

    @Resource(mappedName = "java:/M2M_RESOURCES")
    private DataSource ds;

    @PersistenceContext(unitName = "EM")
    EntityManager em;
    static Logger logger = LogManager.getLogger(ResourceProceduresDaoImpl.class);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss");

    public void create(R resource) {
        em.persist(resource);
        em.flush();
    }

    public R retrieve(Class type, String resourceID) {
        logger.info("ResourceProceduresDaoImpl class=" + type + " resourceID=" + resourceID);
        Object obj = em.find(type, resourceID);
        // logger.info("ResourceProceduresDaoImpl obj="+obj);
        return (R) obj;
    }

    public void update(R resource) {
        em.merge(resource);
    }

    public void delete(R resource) {
        if (!em.contains(resource))
            resource = em.merge(resource);
        em.remove(resource);
    }        
public boolean checkResourceID(String resourceID) {
                boolean ifExists = false;
             
                if (em.createNamedQuery("ResourcePCM.findByResourceID", ResourceParentChildMapping.class)
                    .setParameter("resourceId", resourceID).getSingleResult() == null) {
                    
                        ifExists = true;
                    } 
    
    ..//
                return ifExists;
            }

The JPA for ResourcePCM :

    @Entity
    @Table(name="\"RESOURCE_PCM\"",schema="\"RESOURCES\"")
    @NamedQueries({
       @NamedQuery(name="ResourcePCM.findAll", query="SELECT r FROM ResourcePCM r"),
       @NamedQuery(name="ResourcePCM.findByResourceID", query="SELECT r FROM ResourcePCM r where r.resourceID = :resourceId")
    
    })
    @NamedStoredProcedureQuery(
            name = "generateResourceID", 
            procedureName = "generateResourceID", 
            parameters = { 
                @StoredProcedureParameter(mode = ParameterMode.IN, type = String.class, name = "input"), 
                @StoredProcedureParameter(mode = ParameterMode.OUT, type = String.class, name = "output")
            }
        )
    public class ResourcePCM implements Serializable {
        private static final long serialVersionUID = 1L;
    
        @Id
        @Column(name="\"resourceID\"")
        private String resourceID;
        
        @Column(name="\"structuredResourceID\"")
        private String structuredResourceID;
    
        @Column(name="\"parentID\"")
        private String parentID;
    
        @Column(name="\"resourceType\"")
        private Integer resourceType;
        
        @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
        @JoinColumn(name="\"resourceID\"",referencedColumnName="\"resourceID\"")
        private Set<ResourceACP> resourceACP;

..///
}

So like this only in queries there are significant allocations of memory and I am unable to figure out the cause.

Is it the JPA ? Or the way EntityManager is invoked ?

PS: I use JNDI lookup for my Beans rather than injection with @EJB or @Inject, if this would make a difference ?

EDIT

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_1.xsd">
     <persistence-unit name="EM" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>java:/M2M_RESOURCES</jta-data-source>
            <class>package.jpa.ResourceBase1</class>
            <class>package.jpa.ResourceBase2</class>
            <class>package.jpa.ResourceBase3</class>
            <class>package.jpa.ResourceBase4</class>
            <class>package.jpa.ResourceBase5</class>
            <class>package.jpa.ResourceBase6</class>  

..///

            <!-- Converters -->
            <class>package.mapping.DBJsonConverter</class>       
            <properties>                                                
            <property name="eclipselink.target-server" value="JBoss"/>
            <property name="eclipselink.target-database" value="PostgreSQL" />
        </properties>
    </persistence-unit>
</persistence>

EDIT2:

Incoming References to byte[] :

enter image description here

Incoming references expanded:

enter image description here

The difference between two snapshots taken between 5k request and 10k request load:

enter image description here

postgresql-ds.xml

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
    <datasource jndi-name="java:/RESOURCES" pool-name="RESOURCES" enabled="true" use-java-context="true" use-ccm="true">
        <connection-url>jdbc:postgresql://[hostname]:[port]/[schema]</connection-url>
        <driver>postgresql-42.2.5.jar</driver>
        <pool> 
            <min-pool-size>200</min-pool-size> <max-pool-size>400</max-pool-size> 
            <prefill>true</prefill> 
        </pool> 
        <security>
            <user-name>[userName]</user-name>
            <password>[password]</password>
        </security>
        <timeout>
            <blocking-timeout-millis>800</blocking-timeout-millis>
        </timeout>
        <statement>
            <prepared-statement-cache-size>100</prepared-statement-cache-size>
            <share-prepared-statements>true</share-prepared-statements>
        </statement>
    </datasource>
</datasources>
0

There are 0 best solutions below