这是我们讨论过的另一个问题@nebhale。
最近一直在研究一些 Java 内存问题,我从 Heroku 看到了以下两篇文章(我应该称它们为“无法命名的那些”吗?:P):
这表明调整MALLOC_ARENA_MAX
可以帮助解决应用程序中的内存问题。 似乎它也给Hadoop带来了问题,尽管这可能是他们自己监控 VMEM 的错误(说真的,伙计们,为什么?!)。
在我自己的测试中,我注意到设置MALLOC_ARENA_MAX
似乎有助于减缓内存增长,尽管它_不_完全阻止它。
设置MALLOC_ARENA_MAX
会对性能产生影响(我一直将其设置为2
,正如 Heroku 所建议的那样),但结果如下:
MALLOC_ARENA_MAX
块正在使用中(默认为8 * cpu_count
),则获取一个。malloc
ing新内存时,如果独占一个arena,不需要加锁。glibc
引入 arenas 之前,所有线程都在争夺相同的内存。glibc
将竞技场标记为“空闲”,但不会_不_将其返回给操作系统。无论如何,这是我的理解。 所以我认为CF上的大部分Java应用基本不受影响,原因如下:
min_threads = max_threads
。 大多数线程都是长期存在的,并且会处理大量请求。malloc
- 它在启动时mallocs
堆空间,然后根据需要写入它。 据我所知,一旦线程运行,就不需要执行操作系统级别的malloc
,这意味着我们永远不会有操作系统级别的内存争用(这已被拉入 Java 运行时)。ByteBuffer
之类的东西可能会导致malloc
调用-对此不确定。综上所述,在深入研究之后,似乎设置MALLOC_ARENA_MAX
可能只是隐藏了一个更深层次的问题,我不确定我是否会建议默认设置它。 它似乎并没有对性能产生负面影响,但是我测试的两个应用程序在设计上实际上都是非性能的,所以不要把它当作福音。
我最初认为这里可能存在内存问题,但我不再那么确定了。 我认为如果发生内存泄漏,会发生以下情况:
无限MALLOC_ARENAS_MAX
cgroup
OOM 杀死他。MALLOC_ARENAS_MAX
设置为2
cgroup
OOM 杀手锏。(实际的分配决策要复杂得多——这已大大简化。请参阅了解 glibc malloc以获得深入的解释)。
这可以解释为什么我看到pmap
报告的堆空间(它_不是_Java堆!)在我的一次测试运行中上升和上升 - 本机代码的某处存在内存泄漏,竞技场得到了填满了,一旦它们满了,它就不得不回退到使用本机堆。
尽管如此,可能应该为各个线程使用的本机内存留出一些余量。 如果它足够小,它可能会留在计算器的“原生”部分。 否则,由于它与使用的线程数有关,因此可能需要以某种方式计算。
不管设置它的决定如何,我_do_ 认为记录它会非常有用(以及它与 Java 的关系等),就像提供指向其他glibc
配置环境变量的链接一样。 查找这些信息并不像我希望的那样容易。 我认为这也应该记录在其他构建包中——尤其是 Ruby 和 Go,更有可能看到内存领域的问题——请注意,Heroku 示例都谈到了 Ruby。
@ipsi你知道 #160 和 #163 吗?
我刚刚收到来自 SAP 的@TimGerlach的一条推文,他似乎也对这方面的改进感兴趣。 @TimGerlach ,您能详细说明您的要求吗?
这可以解释为什么我看到 pmap 报告的堆空间(不是 Java 堆!)在我的一次测试运行中上升和上升 - 本机代码的某处存在内存泄漏,arenas 被填满,有一次它们已经满了,它不得不回退到使用本机堆。
您是否查看过 Evan Jones 撰写的这篇文章:
TL;DR:始终关闭 GZIPInputStream 和 GZIPOutputStream,因为它们通过 zlib 使用本机内存。 要追踪泄漏,请使用 jemalloc 并使用 MALLOC_CONF 环境变量打开采样分析。
最近 Heroku发表了一篇关于在 Kafka 中追踪类似错误的博客。 GOV UK GDS 团队关于调试本机内存泄漏的文章也可能会有所帮助。
Evan Jones 还写了一篇关于 Java 的 ByteBuffer 中的本机内存泄漏的博客。
感谢@lhotari提到并指出我这个问题。 我将详细说明#319,因为它与我们的主题更相关。
@lhotari我知道第一个问题-不知道第二个问题。 据我所知,实际上存在一个 HotSpot 错误,这可能也是您所看到的: http ://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8164293
我看到了 GZIP 的东西,甚至用 JEMalloc 运行了我的应用程序,但没有看到他们报告的相同问题。 鉴于此问题 (a) 仅出现在 Java 8 中,并且 (b) 在禁用 HotSpot 时消失,我怀疑有多个问题可能导致应用程序随着时间的推移增加内存。
@ipsi感谢您指出 JDK 错误。
您是否看过我在https://github.com/cloudfoundry/java-buildpack/issues/163#issue -60842702 中提出的假设?
一种假设是调整CodeCacheExpansionSize
和MinMetaspaceExpansion
也会减少 malloc 内存碎片。
必须有多个因素导致进程 RSS 增长缓慢的相同症状。 这是提交 #163 的主要原因。
你好呀,
我注意到 TieredCompilation 似乎正在导致持续增长。 禁用 TieredCompilation (-XX:-TieredCompilation) 已经阻止了这种增长在我们的几个应用程序(全部使用 jdk8)上发生。 我今天向 Oracle 提交了一个错误以进行评估,这可能与已经提到的错误有关。 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8164293
只是想我会提到它,以防这对您有所帮助。
/dom
仅供参考,我提出的错误已在https://bugs.openjdk.java.net/browse/JDK-8164293中标记为已解决,目标版本为 8u152,预计发布日期为 2017-10-16。
嗯,这是一个有趣的约会。
仅供参考,该错误已被移植到已发布的 8u131: https ://bugs.openjdk.java.net/browse/JDK-8178124
嗯,这是个好消息。 我将把它开放几周,以便人们针对 v3.16 和 v4.0 进行测试,并让我知道是否仍有未解决的问题。
没有投诉,所以我要关闭它。
最有用的评论
你好呀,
我注意到 TieredCompilation 似乎正在导致持续增长。 禁用 TieredCompilation (-XX:-TieredCompilation) 已经阻止了这种增长在我们的几个应用程序(全部使用 jdk8)上发生。 我今天向 Oracle 提交了一个错误以进行评估,这可能与已经提到的错误有关。 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8164293
只是想我会提到它,以防这对您有所帮助。
/dom