3年前 (2020-12-11)  jvm |   抢沙发  468 
文章评分 0 次,平均分 0.0

本文讨论如何使用NetBeans Profiler探查器来定位Java应用程序中的内存泄漏。

什么是内存泄漏?

正如维基百科所说:“内存泄漏是计算机程序在不再需要时无法释放内存的一种特殊的无意内存消耗。”。任何用任何编程语言编写的程序都可能发生这种情况,Java也不例外。

许多用户认为java VM会自动从内存中释放未使用的对象,但事实并非总是如此。有几种情况下无法释放对象和内存泄漏。一种常见的情况是,一个占用大量内存的对象可能会被无意地保存在内存中,例如,当项目已经关闭时,netbeanside中的一个项目实例。另一种常见的情况是,随着时间的推移,小对象不断添加到集合中,但它们从未从集合中移除,例如在图形编辑器或游戏中缓存坐标。

如何检测内存泄漏?

在第一个场景中,当一个(或几个)对象在某个操作后仍保留在内存中时,内存泄漏检测通常是通过比较操作之前获取的内存快照与操作后获取的快照来完成的,然后在heap walker工具中搜索对该对象的不必要引用。

本文将讨论第二种情况,当有许多小对象在不释放的情况下不断累积。这种类型的泄漏可能更难检测,因为它通常与任何具体操作无关,并且在程序长时间运行之前不会占用大量内存。这种情况非常危险,尤其是对于预期会长时间运行的javaee应用程序。一段时间后,泄漏开始消耗内存,可能会降低应用程序的性能,或者在没有任何可见原因的情况下导致OutOfMemoryError崩溃。

即使您的应用程序似乎没有任何问题,在发布应用程序之前,最好验证一下您的应用程序是否包含任何潜在的内存泄漏。为此,NetBeans Profiler为您提供了特殊的度量标准,可以可靠地发现大量持续泄漏的小对象,即幸存代度量。您可以在监视模式下启动应用程序,而无需任何分析开销,并查看图形以查看应用程序是否随时间泄漏。

幸存代Surviving Generations指标意味着什么?

仅靠一行代码很难定义幸存代指标,因此让我们定义一个三行代码:

  • 生成是在同一GC间隔内(在两个垃圾回收之间)创建的一组实例
  • 幸存的一代是至少在一次垃圾回收中幸存的一代。它的垃圾回收的唯一标识是
  • Surviving Generations(metrics)value是堆上当前活动的不同存活代数(具有不同生成年龄的代数)

通常在一个应用程序中有几个长期存在的对象(如应用程序的主JFrame等)。在应用程式执行阶段,幸存代的年龄会增加,但仍代表一个或几个幸存代。

大多数应用程序也有短生命周期的对象,这些对象的创建非常频繁(例如Dimension等),但是这些对象很快就会被释放,通常只在几个垃圾回收中。这意味着它们只代表少数幸存的几代人(1、2、3代人等)。

如果我们合并以上两种情况,典型应用程序中的存活代总数是相当稳定的。例如,您可能有代表3个幸存代的长寿命对象,以及代表(例如)5个幸存世代的短命对象,这意味着在应用程序运行期间将有大约8个幸存的代。

当然,在某些应用程序中,例如Swing应用程序,对话框和其他组件是在运行时创建的,因此幸存的代数会有所增长。但是经过一段时间后,幸存的代数应该会变得稳定,因为所有的长寿命对象都已经创建,而新创建的短寿命对象也会定期从堆中释放出来。

但是,如果应用程序中存在内存泄漏,使新创建的对象无法从堆中释放(例如,存储在集合中且从未移除的对象),则存活的代数会增加。为什么?因为在每两个垃圾收集之间会创建新一代(泄漏对象),并且在每次连续的垃圾收集中都会生存。在运行期间,存活代的数量会增加,而这正是幸存代的度量标准能够检测到的,而不管这种泄漏浪费了多少内存。这就是为什么使用“幸存代”度量可以帮助您更快地发现内存泄漏,在它消耗整个堆并导致OutOfMemoryError之前。

如何使用NetBeans Profiler?

NetBeans Profiler是NetBeans IDE当前版本的常规安装的一部分。如果您使用的IDE的旧版本不包含所有探查器功能(NetBeans IDE 6.1或更早版本),则可能需要下载并安装NetBeans profiler安装程序包。

发现漏洞

1. 下载并安装netbeanside。

2. 打开要检查是否存在内存泄漏的项目。

3. 从主菜单中选择Profile>profileproject开始分析项目,如果要将NetBeans探查器附加到外部应用程序,请选择“附加探查器”。

4. 选择监视器模式并单击运行。(您不需要监视应用程序的线程)

内存泄露和内存溢出

5. 使用NetBeans Profiler控制面板中的VM telemetry按钮打开小遥测图(菜单Profile/View/telemetry Overview)或大内存(GC)图,并在应用程序运行时观察red Surviving Generations度量线的行为。应用程序在监视模式下以实际工作负载运行的时间越长,内存泄漏分析就越精确。

内存泄露和内存溢出

VM遥测概述,显示应用程序启动后幸存代的值是如何增加的(存活代的确切数量并不重要)。如果该值在运行时继续增加,则应用程序很可能会泄漏。

通常,在应用程序启动期间,幸存代的值开始增长,但经过一段时间后,它应该达到某个稳定的极限并趋于稳定。当发生这种情况时,它表示没有对象被连续创建和泄漏。如果存活的代数继续增长(不管增长速度有多快),那么应用程序很可能会泄漏。

如果在监视期间使用幸存代度量发现内存泄漏,则NetBeans Profiler使您能够轻松地在应用程序中找到创建泄漏对象的代码并解决问题。

发现内存泄漏源头

要查找可疑代码,请执行以下步骤。

1. 将分析模式切换到内存模式,然后选择记录堆栈跟踪进行分配。

内存泄露和内存溢出

2. 打开实时结果,然后单击Generations列标题,按幸存的Generations值对结果进行排序

内存泄露和内存溢出

显示连续释放的浮动[]和不连续创建的浮动项[]和结果。这是一个潜在的内存泄漏,即使它们不消耗太多内存。

3. 右键单击具有持续增长的生存代值的类,然后在弹出菜单中选择“获取快照并显示分配堆栈跟踪”。

内存泄露和内存溢出

IDE显示将打开堆栈跟踪,使您能够找到可能是泄漏源的代码。您可以右键单击类名,然后在弹出菜单中选择“转到源代码”以在编辑器中打开该类。

按照以下步骤定位代码中创建类实例的所有方法。具有最高存活世代值的方法很可能是泄漏的原因。
内存泄露和内存溢出

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1002.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册