当前位置: 首页>>技术教程>>正文


JAVA内存泄漏与垃圾回收简介

 

内存泄漏

本文介绍内存泄漏是什么以及何时运行垃圾收集器。发生内存泄漏的情况是不再使用对象,并且垃圾收集器无法将其从堆中删除-因为仍在引用它们。结果,应用程序消耗了越来越多的资源-最终导致致命的OutOfMemoryError问题(OOM)

内存泄漏导致OOM问题跟JVM堆设置有关,您可以通过设置参数来指定应用程序的初始和最大堆大小:
-Xms<size>
-Xmx<size>
例如:-Xms64m -Xmx512m,表示
JVM以64M开头,如果需要超过64M的内存,则增加内存(最大上限为512),超过上限则会出错。

一般内存泄漏的查找方法及解决办法:

  1. 借助Eclipse检查内存泄漏:
    任何实现了可关闭closable(从1.5开始)(例如输出流自1.5版开始)接口的对象,如果引用被破坏但对象未关闭,则会向您发出警告。
    在EclipseProject > Project settings > JAVA compiler > Errors/Warning > select leak from options(从选项中选择泄漏)。
  2. 检查代码:
    静态字段:静态引用持续存在,因此无法从内存中清除对象。
    守护进程线程:在Web应用程序生命周期之外启动的启动程序容易发生内存泄漏。
    关闭连接:关闭所有文件和数据库连接可以防止内存泄漏。始终关闭连接,直到最终阻塞。
    空分配:在使用列表,Map等之后将null分配给它们,也可以防止内存泄漏。
    自动装箱:每次创建一个新对象时,在传递给函数时,避免将原语与包装器类混合在一起。
  3. 使用工具分析内存使用情况:

来源:甲骨文

像 JProfiler, GC Viewer,VisualVMJConsole 这类的工具能帮助您分析应用程序的性能。
您可以通过在附加了VisualVM的情况下运行应用程序来分析代码。然后执行使您的应用程序变慢的任务,并分析“monitor”和“memory pools”选项卡。
查看内存使用量峰值,然后按执行GC按钮将释放内存。

垃圾收集

Java垃圾回收是Java程序执行自动内存管理的过程。垃圾收集器找到未引用的对象并将其删除以释放内存。
Java垃圾回收是一个自动过程。程序员不需要显式标记要删除的对象。垃圾回收的实现驻留在JVM中。

java.lang.System.gc()方法运行垃圾收集器。

根据甲骨文文档:

主要调用gc方法只是建议Java虚拟机花费更多精力来回收未使用的对象,以使它们当前占用的内存可用于快速重用。当从方法调用返回时,Java虚拟机将尽最大努力从所有丢弃的对象中回收空间。
调用System.gc()实际上等效于该调用:Runtime.getRuntime().gc()

一旦对象符合垃圾收集条件,它不会立即被垃圾收集器销毁,只有当JVM运行Garbage Collector程序时,对象才会被销毁。但是我们不能期望JVM何时运行Garbage Collector。

注意:无法保证上述主动条用GC的方法一定会运行垃圾收集器。

有人将对象引用设置为null以使其符合gc的条件,并使用System.gc()方法显式删除内存。将其设置为null没什么大不了,但是调用System.gc()方法将极大地影响系统性能,因此最好别这么干!

JVM世代:

图片来源: www.oracle.com

堆分为较小的几个部分或者说几代。具体来说,堆的组成部分是:年轻代(Young),老年代(Old, 终身一代)以及永久代(Permanent)。

  1. 年轻代,所有新对象被分配和并开始老化的位置。当年轻代填满时,这会导致minor garbage collection,当老化的对象达到一定的年龄阈值时,它们将从年轻代升级为老年代
  2. 老年代,用于存储长期存在的对象。通常,为年轻代对象设置一个阈值,并且当达到该年龄时,该对象将移至老年代。这一代空间填满内存最终会被垃圾收集。此事件称为major garbage collection
  3. 永久代,包含JVM所需的元数据,用于描述应用程序中使用的类和方法。

这是内存泄漏和垃圾收集器工作的简单而简短的解释。
可以在Oracle文档中研究GC和JVM生成的完整工作,以及如何将对象从一代移动到另一代。参考这里

参考资料

本文由《纯净天空》出品。文章地址: https://vimsky.com/article/4540.html,未经允许,请勿转载。