JPA查询内存泄漏?

问题描述 投票:0回答:1

我们正在使用

Jprofiler
来分析我们的应用程序来解决内存泄漏,并发现以下观察结果:

我们在同一数据集上运行应用程序进行检查,并在标记堆后拍摄多个快照,以查看导致内存泄漏的类。

enter image description here

检查分配后的

byte[]
String
int[]
都指向
JPA
查询。例如
byte[]
的分配热点都指向查询结果:

QuerImpl.getSingleResult
,

QueryImpl.getResultList

EnitiyManger.find

enter image description here

对于

String
jav.util.HashMap$Node
的分配也发现了类似的结果:

enter image description here

JPA 上显示重要分配的一个查询是

checkResourceID
类中的
Dao

@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;
            }

JPA

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;

..///
}

因此,只有在查询中才会有大量内存分配,而我无法找出原因。

JPA
吗?或者
EntityManager
的调用方式?

PS:我使用

JNDI
查找我的 Bean,而不是使用
@EJB
@Inject
进行注入,如果这会产生影响?

编辑

持久性.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>

编辑2:

传入参考

byte[] : 

enter image description here

传入参考文献已扩展:

enter image description here

5k请求和10k请求负载下拍摄的两张快照的区别:

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>
java hibernate jpa memory-leaks eclipselink
1个回答
0
投票

IMO,调查问题的最佳方法是执行大量请求并进行堆转储。 您使用内存分析器分析堆转储 您打开“直方图”视图 您添加“保留堆”列 您对“保留堆”列进行排序。

现在您可以更好地了解对象和内存重新分区。 您可以通过右键单击>列出对象>使用传入引用来找到不同对象的来源。

您可以添加屏幕截图以获得更多帮助。

© www.soinside.com 2019 - 2024. All rights reserved.