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.
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 :
Similar results were found for allocations of String, jav.util.HashMap$Node:
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[] :
Incoming references expanded:
The difference between two snapshots taken between 5k request and 10k request load:
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>





