Java 内存溢出的原因和解决方法
作者:老K
你是否遇到过Java应用程序卡顿或突然崩溃的情况?您可能遇到过Java内存泄漏。在本文中,我们将深入研究Java内存泄漏的确切原因,并推荐一些最好的工具来防止内存泄漏发生。
什么是JAVA内存泄漏?
简单地说,Java内存泄漏是指对象不再被应用程序使用,而是在工作内存中处于活动状态。
在Java和大多数其他编程语言中,垃圾收集器的任务是删除不再被应用程序引用的对象。如果不选中,这些对象将继续消耗系统内存,并最终导致崩溃。有时java内存泄漏崩溃不会输出错误,但通常错误会以java.lang.OutOfMemoryError
JAVA内存泄漏的原因是什么?
当未被引用的对象被归类为引用对象时,就会导致Java内存泄漏。这会阻止垃圾回收器清除内存,导致内存最终耗尽并崩溃。
在内存中,对象可以有两种状态,未引用和已引用。被引用的对象仍然具有到Java应用程序的活动连接,而未被引用的对象则没有。垃圾回收器的任务是查找和标识未引用的对象并将其删除。
垃圾回收器不会清理似乎被引用或正在使用的对象。Java内存泄漏发生在未引用的对象重叠时,这些对象似乎仍在使用中。
我怎么知道是否有内存泄漏?
有几种方法可以检查你的代码,看看它是否发生了内存泄漏。识别泄漏的最简单方法是查找java.lang.OutOfMemoryError错误日志中的事件。如果列出了此事件,您将能够提取有关Java的哪些部分导致了这种情况的进一步详细信息。
您经常会发现有关Java堆空间的详细信息。这可能意味着内存泄漏,资源无法分配,或者堆大小设置得太低。
通常也会发现标记为PermGen空间的错误。在大多数情况下,这不是内存泄漏,而是需要扩展的分配空间。永久生成空间用于存储类对象,如果不扩展,则可以填充。
并不是所有的Java内存泄漏都是相同的,有些漏洞可以比其他漏洞更容易预防。让我们来看看Java内存泄漏的一些最常见的原因。
如何防止JAVA内存泄漏
最常见的内存泄漏类型之一是Java中的对象随着时间的推移而创建,但从未释放。提高性能和防止内存泄漏的一个简单方法是检查代码中静态字段的使用情况。
当您将Java中的任何对象设置为静态时,它会自动将该对象的生命周期附加到JVM本身,因此垃圾收集器从不清除它。正如您可以想象的那样,如果您有许多大对象被设置为静态的,这会在您的代码中造成相当大的问题。
一定要检查static和collections的所有用法。这两者都是导致Java内存泄漏和意外占用内存的最常见原因。
Java内存泄漏的另一个常见原因是存在未关闭的连接。代码中保持连接打开而不关闭连接的任何部分都可能导致内存过度使用。未闭合连接最常见的罪魁祸首是http调用、stream流、FTP站点和数据库访问。
当保持打开状态时,连接会迅速导致堆内存膨胀,并最终导致应用程序崩溃。若要解决此问题,请始终确保在代码中指定了关闭连接的时间。
就像未关闭的连接一样,未关闭的流会导致非常类似的内存泄漏和资源问题。如果未选中,则打开的流将增加堆内存使用量,以达到临界级别,并最终崩溃。在旧版本的Java中,流必须手动关闭,但是现在使用try with resources语句,这可以自动实现。
虽然寻找这些具体的例子可能会有所帮助,但每个程序的编码都是不同的,需要采用不同的方法。如果您要手动查看代码,启用详细的垃圾收集可以帮助您更好地了解哪些内容正在被收集,哪些内容没有被收集。
添加-verbose:gc参数到配置将准确地输出垃圾收集工具正在执行的操作,并让您深入了解可能需要修改的内容。这是一个简单的技巧,但仍然需要你的时间和精力来筛选结果。
对代码进行可靠的审核还可以发现阻碍性能或导致内存泄漏的潜在问题。虽然这看起来很费时,但这通常是处理所有代码的最佳实践,并有助于避免严重的麻烦。
防止JAVA内存泄漏的工具
最后,为了更快地堵住内存泄漏,可以考虑使用Java分析器。探查器允许您监视特定的JVM参数,例如对象创建和垃圾回收。探查器甚至比详细模式更进一步,可以帮助突出显示需要数小时手动跟踪的内存和资源问题。
您可以使用诸如YourKit或JProfiler这样的Java探查器,不仅可以帮助您发现Java代码中的内存泄漏,还可以确定优化和改进的机会。YourKit和JProfiler都有助于删减不必要的代码并识别应用程序中的冗余。虽然这两个示例都不会导致内存泄漏,但它们会影响代码的性能。
JAVA Profiler可以提供以下功能:
- 创建的所有对象
- 所有方法的CPU时间
- 执行期间创建的对象
- 从内存中删除的对象
- 垃圾收集信息
但是,使用一个好的Java分析器只是成功的一半;您还需要监视应用程序的运行状况,因为它会随着时间的推移而变化。为此,您需要将Java分析器与一个著名的Java性能工具配对。
您可以将Java探查器看作是一种反应式工具,而Java性能监视器则是一种主动式工具。您既要确保您的应用程序为您的用户以最佳方式运行,又要避免不必要的停机时间。Java性能监视工具可以测量应用程序的响应能力,监视sla,甚至可以根据用户数据计算许多不同的度量来跟踪用户体验。
我们花了一些时间来寻找一些最好的Java性能工具,可以用来帮助防止Java内存泄漏,并保持代码平稳运行。
以下是我们精选的最佳JAVA性能工具:
- SolarWinds AppOptics(免费试用)提供多种应用程序的深度视觉效果和报告功能。
- DataDog Java性能监控工具平衡了易用性,同时优先考虑了主动特性
- VisualVM是一个简单的Java探查器,非常适合基本的故障排除。
- JProfiler一种付费的Java评测器,可以检测不同级别的大量bug
- Eclipse内存分析器MAT提供了Java堆内存的详细细分,以更好地了解内存泄漏。
- Glowroot一个开源的性能监视器,通过本地浏览器显示数据。
1. SOLARWINDS APPOPTICS(免费试用)
SolarWinds公司的AppOptics是一款全服务的应用程序性能监视器,为大量不同的应用程序构建。虽然AppOptics支持许多程序,但它在监视和排除Java应用程序故障方面做得特别好。
与DataDog类似,AppOptics将强大的功能组合到一个易于使用的仪表板中,允许您自定义和控制您的监视体验。可以从头开始创建警报,也可以从软件附带的预配置模板库中选择警报。
虽然仪表板为您提供了应用程序及其状态的完整概述,但您也可以深入到代码级别并将AppOptics用作性能调谐器。这使得接收实时数据并立即在同一软件中进行故障排除变得很容易。
开发人员可以通过监视Java堆使用率、调用数、错误率和响应时间等指标来监视Java应用程序是否存在内存泄漏或其他许多问题。性能数据也可以通过日志、图表或瀑布跟踪历史地查看,这样可以很容易地缩小时间范围并隔离出问题代码行。
2. DataDog Java性能监控工具
datadog是专门为使监视Java应用程序成为一个简单而直观的过程而构建的。通过交互式仪表板,您可以在服务、客户和端点级别查看Java代码的状态。Datadog通过一个简单的软件即服务(SaaS)模型提供了这些见解。
一旦您输入了代码,DataDog就可以通过自动生成的服务映射识别Java问题、依赖关系和机会。所有这些数据都是从向DataDog报告信息的简单代理安装中提取的。主仪表板将实时和历史性能信息作为可视化和列表项引入,您可以对其进行排序。
总错误、延迟和请求数等指标可以通过仪表板轻松跟踪。可以将此视图更改为网络拓扑视图,以帮助更好地可视化查询之间的关系,以及性能如何影响链下游的其他功能。
通过警报仪表板,您可以根据正常运行时间、异常情况或您设置的特定阈值快速设置通知。很高兴看到这个软件允许您在设置警报模板时组合触发条件。通过尽可能细化您的警报条件,它有助于减少警报疲劳,并保持您的收件箱干净。警报可以通过电子邮件发送,也可以发送到Slack或Pagerduty等其他工具。
当您处理像Java应用程序的性能监视这样复杂的事情时,找到一个既直观又强大的工具会让您耳目一新。您可以免费测试DataDog及其所有功能14天。
3. VisualVM
VisualVM是一个Java故障排除工具,它直接连接到JDK来检测问题,并通过图形界面引起您的注意。开发人员可以查看他们的应用程序堆转储,分析他们的代码,并查看他们的Java应用程序的许多其他见解。因为它直接绑定到您的JDK中,所以可以方便地从您正在工作的地方访问它。
VisualVM相当轻量级,并且直接驻留在本地计算机上,这使得它非常适合在运行中进行故障排除,而且不必依赖基于SaaS的产品。虽然还有其他工具可以提供对Java相关问题的更深入的见解,但VisualVM是一个简单而干净的工具,它非常适合在故障排除过程的开始使用。
当谈到Java分析器时,VisualVM是一个很好的起点,但是您可能需要考虑将其与性能监视工具或其他更详细的探查器配对,以确保找到所有潜在的bug。
您可以在Windows、Linux或macOS操作系统上免费下载VisualVM
4. JPROFILER
JProfiler by EJ Technologies是一款Java评测器,它以易用性和与Java应用程序的轻松集成而自豪。在JVM级别,您可以在执行代码时查看并快速诊断代码中的问题。像Java代码中的内存泄漏这样的问题会在堆内存分析器下快速突出显示。打开和关闭的连接可以通过一个彩色编码的时间线可视化,这样就可以很容易地看到丢失的连接,这些连接保持打开状态并利用资源。JProfiler还有一个内置的堆遍历器,开发人员可以使用它从多个角度查看任何一组对象,以便进行更深入的检查。
默认情况下支持JEE,并将JEE组件分组到调用树中的组中,这样可以更容易地对更高级别的分析数据进行排序,下到粒度级别和其他子系统。
JProfiler与Windows、Linux和macOS兼容,可以使用试用密钥免费测试。
5. Eclipse内存分析器 MAT
为了获得堆内存的详细细分,Eclipse内存分析器被设计成突出显示内存收集中的缺陷并监视Java堆使用的健康状况。存储的任何对象都将显示并在堆中可见,Eclipse内存分析器将监视和报告内存的分配方式以及是否已清除。
仪表板精确地分解堆的大小,以及图表格式中哪些对象的大小最大。您可以配置自己的视图,也可以使用许多预先配置的视图按对象大小、重复类或顶级使用者进行排序。这些指标可以帮助您快速解决堆中的问题,并为优化性能设置更好的策略。
Eclipse内存分析器可以免费下载,并且与Windows、Linux和macOS系统兼容。
6. GLOWROOT
Glowroot是一个开源的java apm,设置起来很快,也很容易开始使用。只需将根目录文件解压并添加到你的浏览器面板上。
如果您需要一个开销极低的工具,Glowroot在资源消耗方面处于类的首位。大量的测试表明,Glowroot在其环境中造成的影响非常小,因此响应时间必须以微秒为单位进行记录。
除了运行极其精简的Glowroot之外,Glowroot还有许多其他特性,可以用来分析和监视Java应用程序。所有数据的实时和历史汇总可以通过MBean支持图表轻松执行实时和长期测试。虽然Glowroot并不是功能最丰富的性能监视器,但它确实提供了可配置的警报功能,从而为长期使用提供了额外的灵活性。
Glowroot可以免费下载,如果你想体验一下这个工具,它还附带了一个方便的演示站点。
https://glowroot.org/overhead.html
选择JAVA性能工具
Java内存泄漏可能会令人沮丧,但是确切地知道它是什么以及如何对其进行故障排除将使处理它们变得更加容易。我们知道Java内存泄漏是由于堆内存中的对象未清理而导致的。让我们回顾一下修复和防止内存泄漏的最佳方法。
使用Java编译器 - 你的工具包是一个很好的选择,这些工具将帮助您节省数不清的调试时间,并有助于突出显示代码中本来很难找到的问题。
使用可信的Java性能监视器 - Java性能监视器不仅可以提醒您代码中的问题,还可以帮助您在应用程序中发现内存泄漏的迹象,以免它影响到您的用户。
审核你的代码 - 在实现新代码时,定期的审核和测试可以起到很大的作用。安排审核以及清理Java将帮助您的应用程序运行更快,并使故障排除变得更容易。
以上就是Java 内存溢出的原因和解决方法的详细内容,更多关于Java 内存溢出的资料请关注脚本之家其它相关文章!