2012-04-11 61 views
26

我还在学习Java的绳索,所以很抱歉,如果有明显的答案。我有一个需要大量内存的程序,我想找出一种方法来减少它的使用,但是在阅读了很多SO问题之后,我有一个想法,那就是在开始优化之前需要证明问题出在哪里。如何在Java中存储配置文件?

这就是我所做的,我在程序的开始处添加了一个中断点并运行它,然后我启动了visualVM并对其进行了配置文件(我也在netbeans中做了同样的事情来比较结果和他们是一样的)。我的问题是我不知道如何阅读,我得到的最高区域只是说char[],我看不到任何代码或任何东西(这是有道理的,因为visualvm连接到jvm,看不到我的源,但netbeans也不会像我在做cpu分析时那样给我看源代码)。

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

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

+0

我使用了一个分析器,它可以显示我分配对象的位置。我不知道VisualVM是否可以做到这一点,但它非常有用。我使用的是YourKit,但它不是免费的(但你可以获得一个eval许可证) – 2012-04-11 15:31:40

+0

@PeterLawrey我实际上阅读了你前面写过的一个答案,你提到yourkit是你的第一选择,我确实查了它(因为你的建议总是很棒),但是它有点贵,我只是在学习。 – 2012-04-11 15:33:50

+0

没有使用仪器代码的东西没有分析仪将能够指出哪个实例==你称为你的来源参考。 – 2012-04-11 16:05:04

回答

22

字符串是有问题的

基本上在Java中,String引用(使用char[]幕后的东西)将智慧主宰最业务应用程序的内存。它们的创建方式决定了它们在JVM中占用的内存量。

仅仅因为它们对于大多数业务应用程序来说如同数据类型一样非常重要,并且它们也是最需要内存的之一。这不仅仅是一个Java事物,String数据类型在几乎每种语言和运行时库中占用大量内存,因为至少它们只是每个字符1个字节的数组,或者更糟糕的是(Unicode),它们是数组每个字符多个字节。

一旦纹上的Web应用程序,也有一个Oracle JDBC的依赖CPU的使用率,当我发现StringBuffer.append()由多个数量级的占主导地位的CPU周期比所有其他方法调用结合,更不用说其他任何单一的方法调用。 JDBC驱动程序做了大量的操作,使用PreparedStatements来处理所有事情。

你是什么人关心你无法控制,不能直接反正

你应该专注于什么是什么在你的控制,这是确保你不抱上引用长于你需要,而且你没有不必要的重复。 Java中的垃圾收集例程经过高度优化,如果您了解它们的算法如何工作,则可以确保您的程序以最佳方式运行这些算法。

Java堆内存不喜欢手动管理存储在其他语言中,这些规则并不适用

什么被认为内存泄漏其他语言是不一样的东西/根源为用Java的垃圾收集系统。

最有可能在Java内存中没有被泄漏的单个超级对象(其他环境中的悬挂参考)占用。

这是最有可能的,因为很多StringBuffer/StringBuilder对象不是第一instantantations适当大小,然后不得不自动增长char[]阵列举行后续append()通话较小的分配的。

由于垃圾收集器的范围和许多其他事情在运行时可能会有所不同,因此这些中间对象可能比垃圾收集器预期的时间长。

示例:垃圾收集器可能会决定有候选人,但由于它认为仍有大量内存需要处理,因此在该时间点刷新它们可能太昂贵了,它会一直等到内存压力升高。

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

这些未引用的对象可能尚未达到垃圾回收器认为需要它们从内存中清除它们的时间,或者可能存在其他对象(例如List)所引用的引用你没有意识到仍然指向那个对象。这在Java中最常被称为泄漏,这是更具体的参考泄漏。

例:如果你知道你需要使用StringBuildernew StringBuilder(4096);不是默认的,这就好比32,并立即开始创建的垃圾,可以代表很多时候你在想什么对象应该创造它来建立一个4K String在尺寸上明智。

你可以发现有多少类型的对象用VisualVM实例化,这会告诉你你需要知道什么。不会有闪光灯指向一个类的单个实例,即“这是大内存消费者!”,即除非您正在阅读的某个char[]只有一个实例大量的文件到,这也是不可能的,因为很多其他类在内部使用char[];然后你几乎已经知道了。

我没有看到OutOfMemoryError

任何提及,你可能没有在你的代码中的问题,垃圾收集系统,只是可能没有得到足够的压力下踢在和释放放置物体你认为它应该清理。什么你认为是一个问题可能不是,除非你的程序崩溃与OutOfMemoryError。这不是C,C++,Objective-C或任何其他手动内存管理语言/运行库。你不能决定什么是在记忆中,或者不在你所期待的细节层面上。

0

如果使用visualVM检查内存使用情况,它将重点放在数据上,而不是方法。也许你的大char []数据是由许多String值引起的?除非使用递归,否则数据将不会来自本地变量。因此,您可以专注于将元素插入大数据结构的方法。要了解精确的语句将导致你的“内存泄露”,我建议你另外

2

我会建议捕获堆转储和使用像Eclipse MAT这样的工具,让你分析它们。有很多tutorials可用。它提供dominator tree的视图,以深入了解堆上对象之间的关系。特别是对于你所提到的,MAT的“GC根源路径”功能将告诉你哪些大部分char [],String []和int []对象被引用。 JVisualVM还可以用于识别泄漏和分配,特别是通过使用分配堆栈跟踪的快照。有很多walk-throughs of the process获取快照并比较它们以找到分配点。

7

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

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

enter image description here

免责声明:我公司开发的JProfiler