内存使用率高 - 应用程序响应慢:已用内存值未减少 + 可用内存值未增加
Posted
技术标签:
【中文标题】内存使用率高 - 应用程序响应慢:已用内存值未减少 + 可用内存值未增加【英文标题】:Memory usages high - Slow application response : Used memory value not decreasing + Free memory value not increasing 【发布时间】:2020-04-03 09:03:26 【问题描述】:当应用程序使用几分钟后,它会慢慢增加 Used 内存值并减少 Free 内存值。几分钟后应用程序变得非常缓慢。为什么不释放内存。
系统配置:
CPU:Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz(处理器数量:4 / CPU 内核数量:8) 内存:30 GB 操作系统:CentOS-7应用配置:
java 版本 "1.8.0_171" -- build 1.8.0_171-b11 apache-tomcat-7.0.55Tomcat 设置
免费 -h 命令
顶部命令
。 .
Used 内存值显示占用 12 GB,Free 内存值显示 600 MB 可用。我执行了多个并发用户搜索并运行 jcmd 命令生成 heapdump.hprof 以分析内存使用情况,并观察到 heapdump 文件大小不超过 600 MB。
已用内存为 12 GB,堆转储为 600 MB - 我不知道为什么内存没有释放或释放。
任何人都可以就如何设置/配置以提高特定硬件配置的内存使用率提出任何建议。
【问题讨论】:
为什么会释放内存?与其担心操作系统内存分配,不如检查应用程序变慢的原因。 当应用程序启动时 - 使用的内存值为 5 到 6 GB,然后每次搜索后,大约 600 到 800 MB 被添加到“已用”内存值中,并且慢慢地,内存消耗增加。一段时间后,总内存使用量达到 12 GB。 GC 应该释放内存,但它没有发生。由于没有足够的内存可用,系统变慢。 根据top
或free
,您无法可靠地知道 GC 在做什么,所以您是在假设。您需要分析您的应用程序以查看实际内存使用情况以及导致速度变慢的原因。
您是否使用任何集合来存储大量数据?如果是,当该集合不再使用包含大数据的集合时,您是否取消引用它?
从 Java 8 开始没有 PermSpace。所以你不必设置 MaxPermSize。您可以尝试为您的应用程序设置 Xms 和 Xmx 吗?分析 GC 日志可能会让您了解应用程序的内存占用情况。
【参考方案1】:
您面临的问题是Memory leak
这是什么?
在计算机科学中,内存泄漏是一种资源泄漏, 当计算机程序错误地管理内存分配时发生 这样就不会释放不再需要的内存。
如上所述:不再需要的内存不会被释放
什么时候发生?
在释放分配的堆之前,分配堆的ref
被释放。而堆的ref
被释放,那么垃圾收集将无法处理分配的堆。换句话说,它不会无法找到孤立的分配堆。
在长时间运行的程序中发生内存泄漏会导致什么?
程序会吃掉内存、CPU资源
它是怎么吃的?
程序不断分配 RAM。但是,不会取消分配它。因此,使用的内存变高并导致运行缓慢和滞后。
它是如何解决的?
如果您使用的是Android Studio,它的intellisense功能会通过黄色高亮标记可能存在内存泄漏的部分代码。如果您将鼠标悬停在突出显示上,它会弹出并显示警告为什么它可能会导致问题。
【讨论】:
【参考方案2】:据我所知,您只是在设置 permSize。同时设置 -Xms 和 -Xmx,以便垃圾收集器在达到这些值时启动并清理堆内存。
【讨论】:
【参考方案3】:我认为服务器没有任何问题,看来问题仅在于您的代码。
如果还没有完成,您可以使用以下方法来提高代码质量,
在 Java8 中,有一个“try with resources”功能,请使用它来关闭所有连接。
如果您有任何不必要的 for 循环,请检查您的代码,该循环只是打印一些记录器并在每次执行搜索功能时运行。
您还可以在您的代码上运行“SonarLint”和“SonarQube”,这将帮助您找出代码中的内存泄漏。
要测试并发搜索,您可以使用 jMeter。
我希望这会有所帮助。
【讨论】:
【参考方案4】:您是否尝试连接分析器来检查导致此问题的数据类型? 像 Visual VM 这样的分析器可以帮助您了解堆的状态、导致增加的原因以及要使用的正确类型的垃圾收集器。
【讨论】:
【参考方案5】:大小的减少可能是由于在转储其堆时,JVM 将首先运行垃圾回收周期以释放任何无法访问的对象。
如果您想更深入地了解内存的使用情况,您应该首先检查垃圾收集器的工作情况。 首先,您使用的标志不处理堆大小
-XX:PermSize -XX:MaxPermSize
用于设置永久代的大小。永久代:永久代是保存类文件的地方。但是将其视为类元数据,而不是实际的对象,它们进入堆(有一些警告)
然后使用 flags-Xms1024m -Xmx1024m
为您的 JVM 正确设置您的首选项,并启用更多日志记录 -verbose:gc -XX:+PrintGCDetails
。
你会得到这样的东西:
Heap
def new generation total 314560K, used 100261K [0x00000000c0000000, 0x00000000d5550000, 0x00000000d5550000)
eden space 279616K, 35% used [0x00000000c0000000, 0x00000000c61e9370, 0x00000000d1110000)
from space 34944K, 0% used [0x00000000d3330000, 0x00000000d3330188, 0x00000000d5550000)
to space 34944K, 0% used [0x00000000d1110000, 0x00000000d1110000, 0x00000000d3330000)
tenured generation total 699072K, used 368281K [0x00000000d5550000, 0x0000000100000000, 0x0000000100000000)
the space 699072K, 52% used [0x00000000d5550000, 0x00000000ebcf65e0, 0x00000000ebcf6600, 0x0000000100000000)
并检查对象的生命周期,看看它们在每次 GC 收集时是如何“老化”的。 下面的这些定义将帮助您更好地理解堆中对象的生命周期(如果您还没有)
堆内存 堆内存是 Java VM 为所有类实例和数组分配内存的运行时数据区域。堆的大小可以是固定的或可变的。垃圾收集器是一个自动内存管理系统,为对象回收堆内存,
Eden Space:最初为大多数对象分配内存的池。
Survivor Space:包含在 Eden 空间的垃圾收集中幸存下来的对象的池。
Tenured Generation 或 Old Gen: 包含在幸存者空间中已存在一段时间的对象的池。
因此,如果您最终使用 OldGen,则会触发 Full GC,这可能表明您有内存泄漏。
这也可能导致java.lang.OutOfMemoryError: GC overhead limit exceeded
errors
在这种情况下,我会进一步检查那里的物体以找到蠕虫。
否则,可能是短期对象的流失率很高,这通常发生在 ETL 应用程序中。尝试检查您的代码以尽可能避免实例化对象(检查享元模式)
如果这些都没有发生,你可以说你的 JVM 是健康的。
【讨论】:
以上是关于内存使用率高 - 应用程序响应慢:已用内存值未减少 + 可用内存值未增加的主要内容,如果未能解决你的问题,请参考以下文章