Java请求占用40-50MB内存(Spring JPA Hibernate)
我正在使用带JPA Hibernate的spring boot。 我正在监视Heap的服务,发现我的每个请求都占用了大约40-50MB的空间 因此,内存会增加,在GC运行几次请求后,它会释放内存,这将永远持续下去 所以我的第一个问题是,这是内存泄漏吗 我也在试图找出是什么导致了这一切。因此,我使用Runtime.getRuntime()freemory和totalMemory()来确定在获取一个db调用并用它填充投影时使用了大约15MB的内存Java请求占用40-50MB内存(Spring JPA Hibernate),java,spring,hibernate,jpa,Java,Spring,Hibernate,Jpa,我正在使用带JPA Hibernate的spring boot。 我正在监视Heap的服务,发现我的每个请求都占用了大约40-50MB的空间 因此,内存会增加,在GC运行几次请求后,它会释放内存,这将永远持续下去 所以我的第一个问题是,这是内存泄漏吗 我也在试图找出是什么导致了这一切。因此,我使用Runtime.getRuntime()freemory和totalMemory()来确定在获取一个db调用并用它填充投影时使用了大约15MB的内存 public interface Recommend
public interface RecommendationProjection {
public String getType();
public boolean getIsOK();
public int getId();
public int getTagCount();
public double getQuality() ;
public LocalDateTime getLastActivity();
}
hibernate返回567条记录,所以基本上我从DB得到的是投影上面567条记录的列表,但我不明白这个对象怎么会占用这么高的内存?是冬眠造成的吗
使用投影时,hibernate查询特定字段或从数据库中获取所有字段
然后我将这个域映射到DTO,它再次使用15-20MB内存?
这是我的DTO
public class RecommendationInfoDTO {
private String type;
private boolean isOK;
private int id;
private int tagCount;
private double quality ;
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss", timezone="IST")
private LocalDateTime lastActivity;
.. getters and setters
}
仅供参考:我使用VisualVM进行监控。
谁能告诉我可能的问题是什么
我也分析了堆转储,但没有得到任何东西
这是我的堆转储差异
我在一个请求中触发了6个hibernate查询和3个简单的普通mysql查询(使用jdbc调用)
问题只是一个休眠调用。我想我的冬眠有什么问题吗?
有什么方法可以进行基于请求的分析吗
Gc/内存图
按大小排序的堆转储
以下是我的观点:
因此,内存会增加,在GC运行几次请求后,它会释放内存,这将永远持续下去
所以我的第一个问题是,这是内存泄漏吗
不一定是内存泄漏。但是,您需要运行并运行应用程序更长的时间,看看在GC周期中内存是如何释放的。只要内存使用率是一个指标,GC就能够回收垃圾,并且内存得到了有效利用
使用投影时,hibernate查询特定字段或从数据库中获取所有字段
否在投影情况下,它仅获取指定的列
然后我将这个域映射到DTO,它再次使用15-20MB内存
不仅是您的DTO,还有hibernate
,在spring数据之上,jpa
将在内部创建自己的对象来完成查询,这些对象可能正在等待GC。只要它们在GC循环后得到回收,并且每次GC后内存使用量没有不断增加,这就是一个健康的迹象
但是,除了每个请求所使用的内存之外,您可能还需要从更大的角度来看问题,其中一些项目(不是详尽/完整的列表)可能是:
最后,您可能希望了解GC并对其进行调优。在我看来,这是正常的行为 所以我的第一个问题是,这是内存泄漏吗 不会。内存泄漏要求内存在其使用寿命之后保持分配状态。由于GC正在清除查询所消耗的总内存空间,因此您没有泄漏,您只是在使用内存 但我不明白的是,这个物体怎么会有这么高的记忆 对象没有占用太多内存,占用内存的是每个查询的567个对象实例 让我们看一看解释原因: 投影的每个实例都包含
- 长度未知的
(字符串不是原语,因此在纯字符计数的顶部有大量的元数据属性,但就说1个字节)字符串
- 分配1个字节的
布尔值
- 每个字节的2
int
- 一个2字节的
双字节
- 和
,它由几个字段组成(因此,让我们乐观地说,是2字节)LocalDateTime
如果您希望占用更少的空间,请重新评估尽可能多地重用数据的方法,以减少必须进行的查询数量。您使用的是哪一版本的Java?请发布获取数据的方式(任何存储库类、自定义查询等)?您应该做的第一件事是确定投影是否正常工作。记录hibernate生成的语句,查看是否选择了所有列或仅选择了投影声明的列。是否可以显示根据最后一列(即大小)排序的堆转储?使用的最小和最大堆大小是多少?使用多长时间你已经运行了你的应用程序,你向你的应用程序发出了多少请求?你有没有收到任何OOM错误?你还可以给你看GC图。我使用Java 8,我已经看到查询投影工作正常。查询只获取特定记录。最小堆512M和最大堆1024M。我正在本地测试它。所以单(没有任何使用40MB的并发请求)我总共使用了6个查询。但只有一个查询正在执行,即获取567行。