如何在Java中记忆配置文件?

我还在学习Java的绳索,如果对此有明显的答案,那就很抱歉。 我有一个占用大量内存的程序,我想找到一种方法来减少它的使用,但在阅读了很多SO问题之后,我认为我需要在开始优化它之前certificate问题出在哪里。

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

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

编辑:理想情况下,我正在寻找能够获取所有物体并按尺寸排序的东西(所以我可以看到哪一个占用内存)。 目前它返回诸如string []或int []之类的通用信息,但我想知道它所指的是哪个对象,所以我可以努力使其大小更加优化。

字符串是有问题的

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

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

一旦在具有Oracle JDBC依赖性的Web应用程序上分析CPU使用情况时,我发现StringBuffer.append()在所有其他方法调用的组合中占据CPU周期的许多数量级,更不用说任何其他单个方法调用。 JDBC驱动程序执行了大量的String操作,这是将PreparedStatements用于所有内容的一种权衡。

无论如何,你关心的是你无法控制的

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

Java Heap Memory与其他语言的手动管理内存不同,这些规则不适用

什么被认为是其他语言中的内存泄漏与Java及其垃圾收集系统不同的原因/根本原因。

Java内存中很可能不会被泄漏的单个超级对象(在其他环境中悬挂引用)消耗掉。

由于StringBuffer / StringBuilder对象在第一个时序上没有适当resize,然后必须自动增长char[]数组以保存后续的append()调用,因此很可能是大量较小的分配。

由于垃圾收集器所处的范围以及许多其他可能在运行时变化的事物,这些中间对象可能会被垃圾收集器保持的时间长于预期。

示例:垃圾收集器可能会确定存在候选者,但是因为它认为仍有大量内存需要在那个时间段将它们清除出来并且它会花费太多时间,并且它会等到内存压力越来越大。

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

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

示例:如果您知道需要使用StringBuilder构建4K String使用新的StringBuilder创建它new StringBuilder(4096); 不是默认值,它就像是32并且会立即开始创建垃圾,它可以代表你认为对象应该是大小明智的很多倍。

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

我没有看到任何提到OutOfMemoryError

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

在JProfiler中 ,您可以转到堆walker并激活最大的对象视图。 您将看到保留最多内存的对象。 “保留”内存是如果删除了对象,垃圾收集器将释放的内存。

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

在此处输入图像描述

免责声明:我公司开发JProfiler

我建议捕获堆转储并使用Eclipse MAT之类的工具来分析它们。 有很多教程可供使用。 它提供了支配树的视图,以提供对堆上对象之间关系的深入了解。 特别是对于你提到的内容,MAT的“GC根路径”function将告诉你哪些char [],String []和int []对象被引用。 JVisualVM在识别泄漏和分配时也很有用,特别是通过使用具有分配堆栈跟踪的快照。 获取快照并比较它们以查找分配点的过程有很多演练 。

Java JDK在bin文件夹下附带JVisualVM ,一旦您的应用程序服务器(例如正在运行),您可以运行visualvm并将其连接到localhost,这将为您提供内存分配并使您能够执行堆转储

在此处输入图像描述

有关如何启用的更详细步骤: http : //sysdotoutdotprint.com/technologies/java/6

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

  • 阅读Josh Bloch的Effective Java Item 6 :(消除过时的对象引用)
  • 使用日志框架在最高详细级别上创建日志实例。