如何在Java中内存配置文件?

2022-09-01 02:09:39

我仍然在学习Java的绳索,所以很抱歉,如果有一个明显的答案。我有一个程序占用了大量内存,我想找出一种方法来减少它的使用,但是在阅读了许多SO问题之后,我有一个想法,即在我开始优化它之前,我需要证明问题出在哪里。

所以这就是我所做的,我在程序的开头添加了一个断点并运行它,然后我启动了visualVM并让它分析内存(我也在netbeans中做了同样的事情,只是为了比较结果,它们是相同的)。我的问题是我不知道如何阅读它们,我得到了最高的区域,我只是说,我看不到任何代码或任何东西(这是有道理的,因为visualvm连接到jvm并且看不到我的源代码,但是netbeans也没有像执行CPU分析时那样向我显示源代码)。char[]

基本上,我想知道的是哪个变量(希望有更多的细节,如哪种方法)正在使用所有内存,所以我可以专注于在那里工作。有没有一个简单的方法来做到这一点?我现在使用eclipse和java进行开发(并专门为分析安装了visualVM和netbeans,但我愿意安装任何你认为可以完成这项工作的东西)。

编辑:理想情况下,我正在寻找一些可以获取我所有对象并按大小排序的东西(这样我就可以看到哪一个占用了内存)。目前,它返回通用信息,如字符串[]或int[],但我想知道它指的是哪个对象,所以我可以努力使其大小更加优化。


答案 1

字符串有问题

基本上在Java中,引用(在幕后使用的东西)将主导大多数业务应用程序的内存。它们的创建方式决定了它们在 JVM 中消耗多少内存。Stringchar[]

仅仅因为它们是大多数业务应用程序作为数据类型的基础,并且它们也是最需要内存的应用程序之一。这不仅仅是Java的事情,数据类型在几乎所有语言和运行时库中都占用了大量的内存,因为至少它们只是每个字符1字节的数组,或者更糟的是(Unicode),它们是每个字符多个字节的数组。String

有一次,在分析一个也具有Oracle JDBC依赖项的Web应用程序上的CPU使用情况时,我发现它比所有其他方法调用的总和主导CPU周期多了好几个数量级,更不用说任何其他单个方法调用了。JDBC驱动程序做了很多很多的操作,有点像使用一切的权衡。StringBuffer.append()StringPreparedStatements

你所关心的你无法控制,无论如何都不能直接控制

你应该关注的是你控制中的内容,即确保你不会坚持引用的时间超过你需要的时间,并且你不会不必要地重复事情。Java中的垃圾回收例程经过高度优化,如果您了解其算法的工作原理,则可以确保您的程序以最佳方式运行,以使这些算法正常工作。

Java 堆内存不像其他语言中的手动管理内存,这些规则不适用

在其他语言中被认为是内存泄漏的内容与Java及其垃圾回收系统中的内存泄漏不是一回事/根本原因。

在Java内存中,最有可能的是,它不会被一个泄漏的uber对象消耗(在其他环境中悬挂引用)。

很可能是许多较小的分配,因为/ 对象在第一个实例化时大小不合适,然后必须自动增加数组以容纳后续调用。StringBufferStringBuilderchar[]append()

这些中间对象的保留时间可能比垃圾回收器预期的要长,因为它们所在的范围以及运行时可能变化的许多其他内容。

示例:垃圾回收器可能会决定有候选项,但是因为它认为还有足够的内存需要使用,因此在那个时间点将它们清除出去可能太昂贵了,并且它会等到内存压力变高。

垃圾收集器现在真的很好,但它不是魔法,如果你正在做退化的事情,它会导致它不能以最佳状态工作。互联网上有很多关于所有版本的JVM的垃圾回收器设置的文档。

这些未引用的对象可能只是没有达到垃圾回收器认为需要它们才能从内存中删除的时间,或者可能有其他对象()持有对它们的引用(例如,您没有意识到仍然指向该对象。这就是Java中最常见的泄漏,更具体地说,这是一个引用泄漏。List

例:如果您知道您需要使用不使用默认值创建4K,则创建它,就像32一样,并且将立即开始创建垃圾,这些垃圾可以表示您认为对象应该大小的许多倍。StringStringBuildernew StringBuilder(4096);

您可以发现使用 VisualVM 实例化了多少种类型的对象,这将告诉您需要了解的内容。不会有一个大的闪光灯指向单个类的单个实例,上面写着“这是大内存消耗者!”,也就是说,除非你正在读取一些大文件的某个实例,这也是不可能的,因为许多其他类在内部使用;然后你几乎已经知道了。char[]char[]

我没有看到任何提及OutOfMemoryError

你的代码中可能没有问题,垃圾回收系统可能没有足够的压力来启动和释放你认为应该清理的对象。您认为有问题的可能不是,除非您的程序崩溃了。这不是C,C++,Objective-C或任何其他手动内存管理语言/运行时。你不能在你期望的细节级别决定记忆中的内容。OutOfMemoryError


答案 2

JProfiler中,您可以转到堆步行器并激活最大的对象视图。您将看到保留最多内存的对象。“保留”内存是删除对象时垃圾回收器将释放的内存。

然后,可以打开对象节点以查看保留对象的引用树。下面是最大对象视图的屏幕截图:

enter image description here

免责声明:我公司开发JProfiler


推荐