Java G1垃圾收集器占用大量内存

3

我有一个大型数据库项目,使用Java和G1垃圾回收器进行解析。当程序运行一段时间后,Java开始占用大量内存。但是当我检查Java堆时,大小要小得多。例如:

  • Java占用20 GB的RAM
  • "jmap -histo" - 显示堆大小约为5 GB的RAM

问题:剩下的内存是什么占用的?这是G1的开销吗?

编辑:以下是统计信息

我的Java进程的RAM统计信息:分配了50GB,消耗了20GB

jmap信息:堆大小约为4GB

Java进程:分配了约50GB,消耗了约20GB
jmap信息:堆大小约为4GB


@Eugene,我在谈论显式的RAM消耗,-Xmx40G,Java消耗20G但堆大小仅为4G。 - Igor Kiulian
哦,所以进程本身消耗了20G,而堆只有4?你是如何测量那20的? - Eugene
@Eugene 我使用 "htop" 监视进程,我添加了一些图片来展示。 - Igor Kiulian
那么也许它在某个时间点使用了20GB的RAM?还是说它是非堆内存? - Holger
1
是的,20Gb是“当前状态”。而当前状态有一个历史。当它在某个时刻需要20Gb时,它必须分配那么多的内存,当它不再需要时,即包含的对象已经被垃圾回收时,没有关于Java堆的知识的外部工具将继续说这个进程已经分配了那么多的内存。而在JVM内部,大部分内存被认为是空闲的,可以用新对象填充。• Off-heap内存可以包括直接字节缓冲区。您可以拥有尽可能多和尽可能大的可用RAM。 - Holger
显示剩余2条评论
2个回答

4
我理解了问题。正如@Holger所提到的,内存是分配给Java进程的,但未完全填充堆内存。但G1分配如此多的内存的原因是:
如果需要分配大量巨大的区域,G1会遇到麻烦。每当对象大小>区域大小的50%时,它们将被创建。它们将浪费空间,因为在该区域中将不会创建其他任何内容。因此,如果其大小为51%,您将浪费该区域的49%。更糟糕的是,如果一个区域为2MB,而您的对象为2.1MB,那么它将浪费第二个区域中的1.9MB。如果您要分配大型对象,请调整您的XX:G1HeapRegionSize。

0

RAM的消耗将会因为巨大的数据库大小和结果集的大小而产生。

尝试以下优化垃圾回收:

  • 注意字符串拼接操作符(+)的使用,改用concat()方法

  • 如果使用Spring,请尝试setFetchSize(每次获取的行数),使用setFetchSize会增加执行时间,但它是内存高效的

  • 删除所有不必要的语句

  • 使用异步执行


谢谢您的回答。但我并不是一次性读取整个数据库,而是使用分页:1)读取少量数据-块;2)处理它;3)保存到数据库。这不应该占用太多GB的RAM。最神秘的是 - 堆比所有内存消耗都要小。问题在于 - 如果不是堆使用了这些内存,那么是什么占用了这些内存呢? - Igor Kiulian
通常情况下,当您指定concat()时,编译器会准确知道该做什么,而(+)则强制编译器理解使用+的上下文,并且+可以与各种数据类型一起使用,进行解释,更不用说字符串连接会对内存造成很大的影响。您可以同时使用concat和toString()。 - Anish
1
@MadMan 这只涉及到一种特定的情况,当您有两个要连接的项目,并且这两个项目都已经是 String 实例时。在这种情况下,String.concat 可能比使用 StringBuilder 更快,因为它的实现会预先创建一个正确大小的数组,并将两个输入字符串直接复制到该数组中,并使用该数组创建一个新的 String 实例(不需要防御性复制)。但是,JVM 专门针对典型的 StringBuilder 使用进行了优化并消除了开销。而 Java 9+ 将完全不同地编译 + 运算符... - Holger
1
@Ani,你把编译器的工作和运行时性能搞混了。所有你提到的分析都将在编译时完成,不会影响运行时性能。一旦你将String.concattoString()组合在参数中,它比+运算符更昂贵,因为这些中间的String实例需要内存,并暗示字符内容的附加复制操作。我不知道为什么你认为它们在使用concat时是免费的,或许是魔术? - Holger
1
@MadMan 从Java 9开始,字符串连接运算符被编译为单个invokedynamic指令,在运行时进行链接,因此,是JRE决定如何实现特定的场景。因此,如果您使用+与正好两个字符串参数,则可能会链接到执行完全相同操作的某些代码,例如String.concat。但更好的是,每个特定的组合都可以链接到在运行时动态生成的专门代码。此外,如果认为有用,它还可以在幕后实现缓存等等... - Holger
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接