面对Java中的OutOfMemory问题

时间:2016-05-09 14:30:28

标签: java arraylist collections memory-leaks message-driven-bean

由于高堆分配,我面临内存不足问题。我从HP Diagnostics工具验证了它,它指向我的代码中的一个部分,我在arraylist中添加元素。我无法弄清楚如何编写此代码以便尽早释放对象。以下是代码:

    private List<UpperDTO> populateRecords(List<BaseEntity> baseEntityList,List<DataEntity> dataEntityList) {

    List<UpperDTO> masterDTOList  = new ArrayList<UpperDTO>();
    if(baseEntityList !=null && baseEntityList.size()>0){
        BigDecimal conId = null;
        for(BaseEntity baseEntity :baseEntityList){
            conId = baseEntity.getConsignmentId();
            ArrayList<StatusData> statusDataList = new ArrayList<StatusData>();
            if(dataEntityList !=null && dataEntityList.size()>0){
                for(DataEntity data : dataEntityList){
                    if(conId.equals(data.getConsignmentId())){
                        //making null to supress from the response 
                        data.setConsignmentId(null);
                        statusDataList.add(TrackServiceHelper.convertStatusDataToDTO(data));
                    }
                }
            }
            masterDTOList.add(TrackServiceHelper.populateDTO(baseEntity, statusDataList));  
        }
    }
    return masterDTOList;
}

public static UpperDTO populateDTO(TrackBaseEntity baseEntity,
        List<StatusData> statusList) {

    UpperDTO upperDTO = new UpperDTO();
    //Setter methods called
    upperDTO.setStatusData(statusList);
    return upperDTO;

}

问题指向代码中的以下行:

    masterDTOList.add(TrackServiceHelper.populateDTO(baseEntity, statusDataList));

这是rest api,它从JMS队列接收消息,MDB监听这些消息。我无法在本地或开发环境中模拟此问题,因为在请求数量很高时性能测试期间会出现问题。我该如何解决这个问题?

这是HP Diagnostics的Collection Leak的堆栈跟踪:

Chart   Collection Class    Contained Type  Probe   Collection Growth Rate  Collection Size Leak Stack Trace    Maximum Size
0, 0, 255   java.util.ArrayList com.rex.ih2.dtos.UpperDTO   gtatsh645   3,848   122,312 java.util.ArrayList.add(ArrayList.java:413)
com.rex.ih2.utils.AppDAO.populateConsignment(AppDAO.java:168)
com.rex.ih2.utils.AppDAO.searchConsignment(AppDAO.java:93)
com.rex.ih2.service.AppService.fetchConDetail(AppService.java:131)
com.rex.ih2.service.AppService.getConDetail(AppService.java:69)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:76)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:607)
org.apache.webbeans.intercept.InterceptorHandler.invoke(InterceptorHandler.java:297)
org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:98)
com.rex.ih2.service.TrackService_$$_javassist_0.getConsignmentDetail(TrackService_$$_javassist_0.java)
com.rex.ih2.beans.TrackBean.action(TrackBean.java:35)
com.tnt.integration.bean.AbstractServiceBean.invokeService(AbstractServiceBean.java:259)
com.tnt.integration.bean.AbstractServiceBean.onMessage(AbstractServiceBean.java:157)
com.rex.ih2.beans.TrackBean.onMessage(TrackBean.java)

2 个答案:

答案 0 :(得分:0)

我同意dcsohi。这实际上是一个设计问题。您可能需要查看以下方法: -

1)列表中添加的对象的大小。如果可以优化。 2)以块的形式处理数据,而不是在列表中一次性添加所有数据。 3)优化JVM参数以增加头部大小,以便它可以处理更多对象。

您可以尝试通过增加测试对象的数量并减少开发环境中的堆大小来模拟这一点,也可以尝试使用相同的卷进行生产转储和运行。

答案 1 :(得分:0)

好吧,在我看来,你只关心DataEntity个对象和BaseEntity对象的“寄售ID”匹配。你真的应该在数据库查询中做这种事情。使用“实体”对象使得看起来您的数据库交互是通过JPA / Hibernate进行的,在这种情况下,您可能希望创建一个通过寄售ID连接两个表的数据库视图,并为您的输出提供必要的信息。接下来,创建与此视图匹配的自定义只读实体。然后,您可以对此视图的查询应用分页(如果仍然需要),并以较小的批次检索信息。