如何使Java应用程序内存高效?

时间:2009-04-25 15:26:25

标签: java memory caching heap objectpool

如何优化具有大量(数百万)长寿命对象的应用程序的堆大小使用? (大缓存,从数据库加载大量记录)

  • 使用正确的数据类型
    • 避免java.lang.String表示其他数据类型
  • 避免重复的对象
    • 如果预先知道值,则使用枚举
    • 使用对象池
    • String.intern()(好主意?)
  • 仅加载/保留您需要的对象

我正在寻找通用编程或Java特定答案。没有时髦的编译器开关。

编辑:

优化可在堆中出现数百万次的POJO的内存表示。

用例

  • 在内存中加载一个巨大的csv文件(转换为POJO)
  • 使用hibernate从数据库中检索数百万条记录

简历回复:

  • 使用flyweight模式
  • 复制写入
  • 不是加载具有3个属性的10M对象,而是使用大小为10M的3个数组(或其他数据结构)更有效吗? (操作数据可能会很痛苦,但如果你真的缺乏记忆......)

12 个答案:

答案 0 :(得分:20)

我建议您使用内存分析器,查看内存消耗的位置并对其进行优化。如果没有定量信息,你最终可能会改变那些无效或实际上让事情变得更糟的事情。

您可以查看更改数据的表示形式,尤其是对象很小的情况。 例如,您可以将数据表表示为一系列列,每列包含对象数组,而不是每行一个对象。如果您不需要表示单个行,这可以为每个对象节省大量开销。例如一个包含12列和10,000,000行的表可以使用12个对象(每列一个)而不是1000万个(每行一个)

答案 1 :(得分:17)

您没有说要存储哪种对象,因此提供详细建议有点困难。然而,一些(非排他性)方法,无特定顺序,是:

  • 在任何地方使用flyweight pattern 可能的。
  • 缓存到光盘。有 numerous缓存解决方案 爪哇。
  • 关于是否存在争论 String.intern是个好主意。看到 问题here。 String.intern()和金额 关于其适用性的辩论。
  • 使用softweak 您可以存储数据的引用 按需重新创建/重新加载。看到 here关于如何使用软 引用缓存技术。

了解有关您正在存储的对象的内部和生命周期的更多信息,可以得到更详细的答案。

答案 2 :(得分:11)

确保对象模型的良好规范化,不要重复值。

嗯,如果它只有数百万个对象我认为我只需要一个体面的64位虚拟机和大量的内存;)

答案 3 :(得分:4)

普通的“分析器”对您没有多大帮助,因为您需要概览所有“实时”对象。你需要堆转储分析器。我推荐Eclipse Memory analyzer

从字符串开始检查重复的对象。 检查您是否可以应用诸如flightweight,copyonwrite,延迟初始化等模式(google将成为您的朋友)。

答案 4 :(得分:3)

看一下这里链接的演示文稿。它列出了常见java对象和基元的内存使用,并帮助您了解所有额外内存的去向。

Building Memory-efficient Java Applications: Practices and Challenges

答案 5 :(得分:2)

您可以在内存中存储更少的对象。 :)使用溢出到磁盘的缓存或使用Terracotta集群堆(这是虚拟的)允许未使用的部分从内存中刷新并透明地重新插入。

答案 6 :(得分:1)

我想在彼得·阿雷迪所做的事情上添加一些东西(不能评论他的回答:()使用内存探查器(检查java memory profiler)总比使用直觉更好.80%我们忽略的例程在其中存在一些问题。而且集合类更容易发生内存泄漏。

答案 7 :(得分:1)

如果你有数百万的整数和浮点数等,那么看看你的算法是否允许用基元数组表示数据。这意味着每个垃圾收集的引用更少,CPU成本更低。

答案 8 :(得分:0)

一个奇特的:保持大多数数据压缩为ram。仅展开当前工作集。如果您的数据具有可以很好地工作的良好位置。

使用更好的数据结构。 java中的标准集合相当占用内存。

[什么是更好的数据结构]

  • 如果您查看集合的源代码,您会看到如果限制自己访问集合的方式,则可以节省每个元素的空间。
  • 集合处理方式的增长对大型集合没有好处。复制太多了。对于大型集合,您需要一些基于块的算法,如btree。

答案 9 :(得分:0)

花一些时间熟悉和调整VM command line options,尤其是那些与垃圾收集有关的问题。虽然这不会改变对象使用的内存,但它会对具有大量RAM的计算机上的内存密集型应用程序产生很大影响。

答案 10 :(得分:0)

  1. Assign null对所有使用variables的{​​{1}}的值。因此no longer
  2. make it available for Garbage collection一旦使用结束,否则GC不会扫描那些。

答案 11 :(得分:0)

1)尽可能使用正确的数据类型

Class Person {
 int age;
 int status;
}

在这里,我们可以在发送Person对象时使用以下变量来节省内存

class Person{
  short age;
  byte status;
}

2)而不是返回新的ArrayList <>();从method,您可以使用Collection.emptyList(),它将仅包含一个元素,而不是默认的10个元素。

例如

public ArrayList getResults(){
    ..... 
    if(failedOperation)
        return new ArrayList<>();
}
//Use this
public ArrayList getResults(){
    if(failedOperation)
       return Collections.emptyList();
}

3)尽可能在方法中移动对象的创建,而不是静态声明,因为对象的字段将存储在堆栈中,而不是堆中

4)使用protobuf,thrift,avro,messagepack之类的二进制格式代替json或XML来减少相互通信