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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/789132/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 13:47:13  来源:igfitidea点击:

How do you make your Java application memory efficient?

javamemorycachingheapobjectpool

提问by Boune

How do you optimize the heap size usage of an application that has a lot (millions) of long-lived objects? (big cache, loading lots of records from a db)

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

  • Use the right data type
    • Avoid java.lang.String to represent other data types
  • Avoid duplicated objects
    • Use enums if the values are known in advance
    • Use object pools
    • String.intern() (good idea?)
  • Load/keep only the objects you need
  • 使用正确的数据类型
    • 避免用 java.lang.String 来表示其他数据类型
  • 避免重复对象
    • 如果预先知道值,请使用枚举
    • 使用对象池
    • String.intern()(好主意?)
  • 仅加载/保留您需要的对象

I am looking for general programming or Java specific answers. No funky compiler switch.

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

Edit:

编辑:

Optimize the memory representation of a POJO that can appear millions of times in the heap.

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

Use cases

用例

  • Load a huge csv file in memory (converted into POJOs)
  • Use hibernate to retrieve million of records from a database
  • 在内存中加载一个巨大的 csv 文件(转换为 POJO)
  • 使用休眠从数据库中检索数百万条记录

Resume of answers:

回复简历:

  • Use flyweight pattern
  • Copy on write
  • Instead of loading 10M objects with 3 properties, is it more efficient to have 3 arrays (or other data structure) of size 10M? (Could be a pain to manipulate data but if you are really short on memory...)
  • 使用享元模式
  • 写入时复制
  • 与加载具有 3 个属性的 10M 对象不同,拥有 3 个大小为 10M 的数组(或其他数据结构)是否更有效?(操作数据可能会很痛苦,但如果你真的内存不足......)

采纳答案by Brian Agnew

You don't say what sort of objects you're looking to store, so it's a little difficult to offer detailed advice. However some (not exclusive) approaches, in no particular order, are:

你没有说你想要存储什么样的对象,所以提供详细的建议有点困难。然而,一些(非排他性)方法,没有特定的顺序,是:

  • Use a flyweight patternwherever possible.
  • Caching to disc. There are numerouscache solutions for Java.
  • There is some debate as to whether String.intern is a good idea. See herefor a question re. String.intern(), and the amount of debate around its suitability.
  • Make use of softor weakreferences to store data that you can recreate/reload on demand. See herefor how to use soft references with caching techniques.
  • 尽可能使用享元模式
  • 缓存到光盘。Java有 许多缓存解决方案。
  • 关于 String.intern 是否是一个好主意存在一些争论。请参阅 此处了解问题。String.intern(),以及围绕其适用性的争论。
  • 利用引用或引用来存储您可以按需重新创建/重新加载的数据。请参阅 此处了解如何将软引用与缓存技术结合使用。

Knowing more about the internals and lifetime of the objects you're storing would result in a more detailed answer.

了解更多有关您存储的对象的内部结构和生命周期的信息会得到更详细的答案。

回答by Peter Lawrey

I suggest you use a memory profiler, see where the memory is being consumed and optimise that. Without quantitative information you could end up changing thing which either have no effect or actually make things worse.

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

You could look at changing the representation of your data, esp if your objects are small. For example, you could represent a table of data as a series of columns with object arrays for each column, rather than one object per row. This can save a significant amount of overhead for each object if you don't need to represent an individual row. e.g. a table with 12 columns and 10,000,000 rows could use 12 objects (one per column) rather than 10 million (one per row)

您可以考虑更改数据的表示形式,特别是如果您的对象很小。例如,您可以将数据表表示为一系列列,每一列都有对象数组,而不是每行一个对象。如果您不需要表示单个行,这可以为每个对象节省大量开销。例如,一个有 12 列和 10,000,000 行的表可以使用 12 个对象(每列一个)而不是 1000 万个(每行一个)

回答by krosenvold

Ensure good normalization of your object model, don't duplicate values.

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

Ahem, and, if it's only millions of objects I think I'd just go for a decent 64 bit VM and lots of ram ;)

咳咳,而且,如果只有数百万个对象,我想我会选择一个像样的 64 位 VM 和大量内存 ;)

回答by kohlerm

Normal "profilers" won't help you much, because you need an overview of all your "live" objects. You need heap dump analyzer. I recommend the Eclipse Memory analyzer.

普通的“分析器”对您没有多大帮助,因为您需要对所有“活动”对象进行概述。您需要堆转储分析器。我推荐Eclipse 内存分析器

Check for duplicated objects, starting with Strings. Check whether you can apply patterns like flightweight, copyonwrite, lazy initialization (google will be your friend).

检查重复的对象,从字符串开始。检查您是否可以应用飞行重量、copyonwrite、延迟初始化等模式(谷歌将成为您的朋友)。

回答by rado

Take a look at this presentation linked from here. It lays out the memory use of common java object and primitives and helps you understand where all the extra memory goes.

看看从这里链接的这个演示文稿。它列出了常见 Java 对象和原语的内存使用情况,并帮助您了解所有额外内存的去向。

Building Memory-efficient Java Applications: Practices and Challenges

构建内存高效的 Java 应用程序:实践与挑战

回答by Alex Miller

You could just store fewer objects in memory. :) Use a cache that spills to disk or use Terracotta to cluster your heap (which is virtual) allowing unused parts to be flushed out of memory and transparently faulted back in.

您可以在内存中存储更少的对象。:) 使用溢出到磁盘的缓存或使用 Terracotta 来集群您的堆(这是虚拟的),允许将未使用的部分从内存中清除并透明地故障返回。

回答by urmalp

I want to add something to the point Peter alredy made(can't comment on his answer :() it's always better to use a memory profiler(check java memory profiler) than to go by intution.80% of time it's routine that we ignore has some problem in it.also collection classes are more prone to memory leaks.

我想补充一点 Peter alredy 的观点(无法评论他的回答:()使用内存分析器(检查java 内存分析器)总是比凭直觉更好。80% 的时间是我们的例行公事ignore 有一些问题。而且集合类更容易发生内存泄漏。

回答by David Plumpton

If you have millions of Integers and Floats etc. then see if your algorithms allow for representing the data in arrays of primitives. That means fewer references and lower CPU cost of each garbage collection.

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

回答by pramodc84

  1. Assign nullvalue to all the variableswhich are no longerused. Thus make it available for Garbage collection.
  2. De-reference the collectionsonce usage is over, otherwise GC won't sweep those.
  1. Assign null值的所有variablesno longer使用。因此make it available for Garbage collection
  2. De-reference the collections一旦使用结束,否则GC不会清除那些。

回答by Saurabh

1) Use right dataTypes wherever possible

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

Class Person {
 int age;
 int status;
}

Here we can use below variables to save memory while sending Person object

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

class Person{
  short age;
  byte status;
}

2) Instead of returning new ArrayList<>(); from method , you can use Collection.emptyList() which will only contain only one element instead of default 10;

2) 而不是返回新的 ArrayList<>(); 从方法中,您可以使用 Collection.emptyList() 只包含一个元素而不是默认的 10 个;

For e.g

例如

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

3 ) Move creation of objects in methods instead of static declaration wherever possible as fields of objects will be stored on stack instead of heap

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

4) Using binary formats like protobuf,thrift,avro,messagepack for reducing intercommunication instead of json or XML

4) 使用 protobuf、thrift、avro、messagepack 等二进制格式来减少相互通信,而不是 json 或 XML