当前位置: 首页 > 科技观察

如何在您的Java应用中查找并修复内存泄漏_1

时间:2023-03-16 14:57:03 科技观察

如何查找和修复Java应用程序中的内存泄漏当性能良好时,当文件大小增加时会发生什么情况?如果发生这种情况,您很可能会遇到内存泄漏。在处理内存泄漏的时候,如果有人问我:“你知道这件事的前因后果,怎么处理吗?”那么,我将作如下回答:1.目标受众虽然总的来说,本文所描述的方法是独立于IDE和操作系统的,但我在这里使用的截图和说明仍然来自FedoraLinux和带插件的Eclipse——开发中。其次,内存泄漏的症状一开始跑得很快,但随着时间的推移会变慢。例如:它可以正常处理少量数据集,但在处理大量数据集时出现严重的性能问题。在您的JVM中,老一代内存的使用量不断增加。在您的JVM中,您会收到内存耗尽的跳转错误。无缘无故的自我毁灭。3.常见的内存泄漏Java中的内存泄漏通常发生在忘记关闭资源,或者对象引用未能释放时。例如:文件/文本缓冲区未关闭。(参见:https://git.eclipse.org/r/#/c/31313/例如)当不使用equals()和hashcode()时,对各种hashmap的引用保持活动状态,例如:importjava.util。地图;publicclassMemLeak{publicfinalStringkey;publicMemLeak(Stringkey){this.key=key;}publicstaticvoidmain(Stringargs[]){try{Mapmap=System.getProperties();for(;;){map.put(newMemLeak("key"),"value");}}catch(Exceptione){e.printStackTrace();}}}各种其他细节(参见:https://www.toptal.com/java/hunting-memory-leaks-in-java#memleak)由引用各种外部类的内部类引起的泄漏。(可以通过将它们设为静态来避免它们,请参阅:https://blogs.oracle.com/olaf/entry/memory_leaks_made_easy)。第四,如何一次性解决?这里有两种方法。首先是尝试“速战速决”。如果失败,那么您必须走很长的路才能找到解决方案。快速修复:使用Eclipse关于内存泄漏的警告(以捕获一些泄漏)。手动禁用和启用代码的各个部分,并使用VisualVM(Jconsole或Thermostat)等工具来观察JVM的内存使用情况。1.快速修复:Eclipse内存泄漏警告/错误。为了符合JDK1.5+代码规范,Eclipse会针对一些明显的泄漏情况向您“抛出”警告和错误。更准确地说,任何使用closable的对象(例如从1.5开始的outputStream)如果其引用被销毁而不是关闭,都会抛出警告。然而,在Eclipse的每个项目中,其泄漏检测功能并不总是开启的。因此,为了提前打开它们,可以到项目设置中打开,如下图所示:这里Eclipse列出了各种内存泄漏:但是,即使使用了Eclipse的这个功能,系统还是检测不到所有因泄漏而关闭的文件。特别是对于遗留(1.5之前)代码,您很可能会遇到泄漏,因为它们仅在使用期间“可关闭”。还有一些时候,文件在深层嵌套中打开/关闭,这也会导致Eclipse无法检测到。所以遇到这种情况,可能需要尝试第二种方法。2.手动禁用和启用代码的各个部分,并使用VisualVM等工具观察JVM的内存使用情况。如果您已经做到了这一步,您将不得不卷起袖子做一些体力劳动。您需要通读所有代码,试图找出泄漏发生的位置。作为帮助,我建议您使用类似VisualVM的东西(当然,Thermostat和MAT也是可以的)。A。配置好VisualVM(1)下载工具。(2)打开终端,进入目录.../visualvm_xyz/bin,运行shell脚本'./visualvm'(或在Windows上运行visualvm.exe)。(3)您将看到主窗口弹出。如果你展开“Local”并双击你正在运行的应用程序(如下图,我的应用程序是一个子Eclipse),你可以看到它的各种属性。(4)在Fedora上使用VisualVM进行故障排除:对我来说,最初我无法连接到我自己的JVM,并且无法运行堆转储和分析。所以我探索了以下步骤:确保以您自己的登录用户身份运行它,而不是使用sudo。执行完整的系统更新(sudoyumupdate)。考虑重新启动是否有帮助。尝试在关闭所有正在运行的Java应用程序后启动VisualVM。(5)添加一些插件。在使用VisualVM之前,我预先添加了一些插件。请点击进入工具->插件->“可用插件”。请选择以下插件(如果您愿意,可以随意浏览并添加更多插件):MemoryPoolVisualGCTerminateApplicationb。使用VisualVM分析运行代码(1)现在运行您的Java应用程序。(2)将VisualVM连接到您的应用程序。(3)执行往往会降低性能的操作。(4)勾选“Monitoring”和“MemoryPool”选项卡。如果您在“监视器”选项卡中看到内存增加,请按“执行GC”(垃圾收集)并监视内存使用量是否减少。(5)如果不减少,则切换到“MemoryPool”选项卡,勾选“OldGen”(初始对象会留在“Eden”,然后通过Survivor空间过渡,比较oldobjects会被移动到“OldGen”池。如果有泄漏,它将出现在Old-Gen池中。)(6)现在返回并注释掉大部分程序代码,以定位应用程序开始变慢的位置。(7)重复上述过程,直到应用程序完全不泄漏为止。(8)然后,经过反复迭代,重新启用各部分代码,查看VisualVM的内存使用情况。一旦您的应用程序再次开始泄漏,就进入导致内存泄漏的函数的方法,进一步缩小您的代码范围。(9)最后,你将能够将问题缩小到特定的类,甚至单个方法。请仔细验证所有文件的buffer是否关闭,HashMap是否使用正确。5.标准化你的代码有时很难确定你的“bling”新代码是否真的比旧代码好。面对这种情况,您需要规范化您的应用程序的性能。您可以在您认为合适的任何位置插入此代码,以获取有关运行时间和垃圾回收次数的信息:longstart=System.currentTimeMillis();..//yourcode..longend=System.currentTimeMillis();System.out.println(“运行时:”+Long.toString(end-start));System.out.println(printGCStats());publicstaticStringprintGCStats(){longtotalGarbageCollections=0;longgarbageCollectionTime=0;for(GarbageCollectorMXBeangc:ManagementFactory.getGarbageCollectorMXBeans()){longcount=gc.getCollectionCount();if(count>=0){totalGarbageCollections+=count;}longtime=gc.getCollectionTime();if(time>;=0){garbageCollectionTime+=time;}}返回“GarbageCollections:”+totalGarbageCollections+"n"+"GarbageCollectionTime(ms):"+garbageCollectionTime;}特别提醒:如果你在主Eclipse中测试,我建议测试一个“干净”的子Eclipse;或者在Eclipse的一些“干净”实例中。因为在这种情况下,其他各种插件不会对标准耗时产生影响。6.附加说明:我个人不使用堆转储,但有些人更热衷于“堆转储”。您可以随时进行堆转储,查看有多少类实例打开以及它们使用了多少空间。您可以通过双击查看特定内容。如果您想知道您的应用程序生成了多少对象,这将很有用。7.我的应用程序没有泄漏,但为什么仍然很慢?当然,也有一种可能:即使你的代码没有泄漏,它仍然运行缓慢。如果是这种情况,您必须执行代码分析。但是,代码分析超出了本文的范围。这是一个很好的YouTube视频,解释了如何使用免费和付费分析器来分析Eclipse,请参见:https://www.youtube.com/watch?v=YCC-CpTE2LU。8.我还能看到什么?此时,您可以潜入并花一到两天时间来修复您的内存泄漏。在此过程中,如果您仍然遇到麻烦,请参考以下链接:捕捉内存泄漏:https://www.toptal.com/java/hunting-memory-leaks-in-java内部类内存泄漏:https://blogs.oracle.com/olaf/entry/memory_leaks_made_easy浏览Oracle的JVMGC指南:www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html原标题:HowtoFindandFixMemoryLeaksin您的Java应用程序,作者:LeoUfimtsev