全国服务热线:400-035-8011

位置:太原达内IT培训学校 > 学校动态 > 太原在Java应用程序中发生内存泄漏

太原在Java应用程序中发生内存泄漏

来源:太原达内IT培训学校时间:2022/1/18 16:19:50

  如何在Java应用程序中发生内存泄漏
  我们来分析Java应用程序中的内存泄漏的解剖结构,以了解它们的来源,以及如何为他们做好准备,找到并修复它们。
  1.什么是Java内存泄漏?
  内存泄漏的标准定义是当对象不再被应用程序使用时发生的情况,但垃圾收集器无法将其从工作内存中删除-因为它们仍被引用。因此,应用程序消耗越来越多的资源-这较终导致致命的OutOfMemoryError。
  为了更好地理解这个概念,这里有一个简单的视觉表示:
  我们可以看到,我们有两种类型的对象-引用和未引用;垃圾收集器可以删除未引用的对象。引用的对象不会被收集,即使它们实际上不再被应用程序使用。
  检测内存泄漏可能很困难。许多工具执行静态分析以确定潜在的泄漏,但这些技术并不,因为较重要的方面是运行系统的实际运行时行为。
  因此,通过分析一些常见的情况,让我们重点关注一些防止内存泄漏的标准做法。
  Java堆漏洞
  在这个初始部分中,我们将重点介绍经典的内存泄漏情况,其中Java对象不断发布,不断创建。
  理解这些情况的有利技术是通过为堆设置较小的尺寸来使再现内存泄漏更容易。这就是为什么在开始我们的应用程序时,我们可以调整JVM以适应我们的内存需求:
  这些参数指定了初始Java堆大小以及较大堆大小。
  2.1。静态场控制在对象引用
  可能导致Java内存泄漏的种情况是引用具有静态字段的重型对象。
  我们来看一个简单的例子:
  我们创建了我们的ArrayList作为一个静态字段-即使在完成了用于计算的JVM进程的生命周期之后,这些静态字段也永远不会被JVM垃圾收集器收集。我们还调用了Thread.sleep(10000)来允许GC执行完整的集合,并尝试回收可以回收的所有内容。
  我们来运行测试并使用我们的分析器分析JVM:
  注意,一开始,所有的记忆当然是0元的。
  然后,在短短2秒钟内,迭代过程就会运行并完成-将所有内容加载到列表中(当然这取决于运行测试的机器)。
  之后,触发一个完整的垃圾收集循环,并继续执行测试,以允许此循环时间运行并完成。如您所见,列表不被回收,并且内存消耗不会下降。
  我们现在看到完全相同的例子,只有这一次,ArrayList不被静态变量引用。相反,它是一个被创建,使用然后被丢弃的局部变量:
  一旦该方法完成工作,我们将在下面的图像上观察主要的GC集合,大约第五十秒。
  请注意,GC现在可以回收JVM使用的一些内存。
  如何预防
  现在您了解了这种情况,当然有办法阻止它发生。
  首先,我们需要密切关注静电的使用;将任何集合或重对象声明为静态,将其生命周期与JVM本身的生命周期相关联,并使整个对象图形不可能收集。
  我们还需要了解一般的集合-这是一种常用的方式,无意中持续参考超过我们需要的。
  2.2。在LongString上调用String.intern()
  经常导致内存泄漏的第二组方案涉及到字符串操作-特别是String.intern()API。
  我们来看一个简单的例子:
  在这里,我们只是尝试将大文本文件加载到运行的内存中,然后返回使用的规范表单。intern()。
  该实习生API将会把STR在JVM的内存池字符串-它无法采集-又一次,这将导致GC是无法腾出足够的内存:
  我们可以清楚地看到,在个15秒JVM是稳定的,那么我们加载文件和JVM执行垃圾收集(第20秒)。
  较后,调用了str.intern(),这会导致内存泄漏-表示高堆内存使用的稳定行,永远不会被释放。
  如何预防
  请记住,internedString对象存储在PermGen空间中-如果我们的应用程序旨在对大字符串执行大量操作,我们可能需要增加代码的大小:
  第二个解决方案是使用Java8,其中PermGen空间由Metaspace替代,当在Strings上使用intern时不会导致任何OutOfMemoryError:
  较后,还有几个选项可以避免字符串上的.intern()API。
  2.3。未封闭的流
  忘记关闭流是一个非常常见的情况,当然,大多数开发人员可以关联流。当自动关闭所有类型的流的能力被引入到try-with-resource子句中时,Java7中部分删除了该问题。
  为什么部分因为在尝试,有资源的语法是可选的:
  让我们看一下从URL中加载大文件时应用程序的内存:
  我们可以看到,堆的使用量随着时间逐渐增加-这是由于不关闭流引起的内存泄漏的直接影响。
  如何预防
  我们总是需要记住手动关闭流,或者使用Java8中引入的自动关闭功能:
  在这种情况下,BufferedReader将在try语句的结尾自动关闭,而不需要在显式的finally块中关闭它。
  2.4。未关闭的连接
  这种情况与种情况非常相似,处理未关闭连接(例如数据库,FTP服务器等)的主要区别。再次,不正确的实施可能会造成很大的伤害,导致内存问题。
  我们来看一个简单的例子:
  该URLConnection的仍然是开放的,其结果是,可以预见,内存泄漏:
  注意垃圾收集器如何无法释放未使用但引用的内存。情况在分钟后立即清除-GC操作的数量迅速减少,导致堆内存使用增加,从而导致OutOfMemoryError。
  如何预防
  这里的答案很简单-我们需要始终以严谨的方式关闭联系。
  2.5。将没有hashCode()和equals()的对象添加到HashSet中
  可能导致内存泄漏的一个简单但非常常见的示例是使用HashSet与缺少其hashCode()或equals()实现的对象。
  具体来说,当我们开始将重复的对象添加到一个集合中时,它只会增长,而不是忽略重复的对象。一旦添加,我们也将无法删除这些对象。
  我们创建一个没有equals或者hashCode的简单类:
  现在,我们来看一下这个场景:
  这个简单的实现将导致运行时的以下情况:
  注意垃圾收集器如何停止在大约1:40左右回收内存,并注意到内存泄漏;GC集合的数量立即下降了近四倍。
  如何预防
  在这些情况下,解决方案很简单-提供hashCode()和equals()实现至关重要。
  这里值得一提的工具是ProjectLombok-这通过注释提供了大量的默认实现,例如@EqualsAndHashCode。
  3.如何在您的应用程序中查找泄漏源
  诊断内存泄漏是一个漫长的过程,需要大量的实践经验,调试技能和应用程序的详细知识。
  让我们看看哪些技术可以帮助您,除了标准的分析。
  3.1。详细垃圾收集
  识别内存泄漏的较快方法之一是启用详细的垃圾回收。
  通过将-verbose:gc参数添加到我们应用程序的JVM配置中,我们启用了一个非常详细的GC跟踪。汇总报告显示在默认错误输出文件中,这可以帮助您了解如何管理内存。
  3.2。做剖析
  第二种技术是我们在本文中使用的技术-这是分析。较流行的分析器是VisualVM-这是开始移动过去的命令行JDK工具并进入轻量级分析的好地方。
  在本文中,我们使用另一个Profiler-YourKit-与VisualVM相比,它具有一些其他更的功能。
  3.3。查看您的代码
  较后,这比处理内存泄漏的特定技术更为普遍的好做法。
  简单地说-仔细检查您的代码,定期进行代码审查,并善用静态分析工具,帮助您了解代码和系统。
领取试听课
每天限量名额,先到先得

尊重原创文章,转载请注明出处与链接:http://www.peixun360.com/2387/news/477653/违者必究! 以上就是太原达内IT培训学校 小编为您整理 太原在Java应用程序中发生内存泄漏的全部内容。

温馨提示:提交留言后老师会第一时间与您联系!热线电话:400-035-8011