在Java中减少内存消耗

11

我曾参与过一些旨在提高性能和降低内存消耗的项目。但是相信我,在Java中控制内存消耗已经很困难了。

这个维基页面上说,关于“Java程序速度”,“在低级和数字基准测试方面,Java在某些情况下与C++相等。”

这些统计数据并没有显示时间计算性能基准测试中有太大的差异。然而,Java中的内存使用量比C++要高得多,因为如上述维基链接中所述,在Java中每个对象需要8字节开销,每个数组需要12字节开销(32位;在64位Java中是两倍)。

现在的问题是人们采取什么措施来最小化Java中的内存利用率?

请注意,我非常关注内存而不是性能,因为我想不到任何比“撰写更好的程序”和“正确调整JDK中的内存”更好的方式。


1
你不能像C++那样在Java中优化内存占用。如果内存是主要限制因素,那么你需要使用Java的原因是什么? - Daniel Moses
Java在64位程序中使用4个额外字节作为非double对象的头部。在64位JVM中,Java通常对32GB以下的内存使用32位引用,而C/C++ 64位程序通常使用64位指针。 - Peter Lawrey
安舒,Java的哲学并不关心使用了多少RAM,对于Java来说,重点是可扩展性、性能和标准化。如果你想要拥有大部分Java优势但轻量级的东西,可以考虑看看GOLANG,它是介于Java和C++之间的一种语言。 - deFreitas
如果正确配置,JVM可以进行垂直扩展,优化内存使用以适应当前负载。所选的垃圾收集器是主要的基础组件之一,其设置可以影响整个项目。使用G1 GC并避免“激进堆”方法。更多细节请参阅文章“使用正确的垃圾收集器最小化Java内存使用”https://www.javacodegeeks.com/2017/11/minimize-java-memory-usage-right-garbage-collector.html - Ruslan
4个回答

6

根据你的工作需求,你可以从不同的编程实践中受益,例如:

  • 在实际使用之前,限制初始化变量的数量。
    • 这是一个常见的编程技巧。初始化了一段时间不需要的变量会占用不必要的内存,可能浪费资源。
  • 适用时通过静态对象进行对象缓存。
    • 我曾在反射密集型应用程序中使用过这种方法,在循环中获取对象成员列表,根据情况可以显著提高性能。
  • 适用时进行对象池化
  • 如果您正在编写多线程应用程序,则可以利用线程池来提高性能,限制创建和启动新线程的工作量。

3
对象池(甚至更为严格的线程池)实际上倾向于增加内存使用,以提高性能。它的整个目的在于,“保留你当前不使用的对象”,基于这个假设,你很快就会再次需要它们。因此,对象池可以被视为一种优化技巧。 - cHao
很好的发现,完全正确。它应该根据应用程序的需求谨慎使用,并基于情况进行使用。它可能会提高性能,但确实会增加内存使用量。它通常用于快节奏的处理应用程序,如游戏等。线程池也是如此。 - AdamM
1
实际上,情况并不是那么绝对。对象池可以在某些情况下减少内存占用,特别是当您创建大量对象、短暂使用它们然后丢弃它们时。如果您一直这样做,不仅会产生GC开销,而且有可能GC无法跟上其速度。因此,与其不断创建新对象,拥有一小组可重复使用的对象可能更好。 - Nim

3

在Java中,有两个管理内存的动机。

1. 避免频繁创建/删除对象。

这反过来避免了GC经常唤醒,因为这可能会导致一个或多个执行线程挂起。

避免临时/永久的内存空洞

2. 减少VM的总内存消耗

如果您的VM将在具有严格内存限制的环境中运行,则需要这样做。

从内存角度来看,良好编写的Java程序应尽力实现上述两点。要实现1,您应该执行以下操作。

  • 优先使用静态内存分配,即每个VM只分配一次,而不是动态内存分配。

  • 避免在函数内创建临时对象,为此大多数对象可以实现reset()方法,以允许重用对象

  • 了解您正在使用哪个API,例如,如果使用String,则将创建与修改数量相同的实例。自动装箱类型也适用。

上述观点还有助于管理或控制第2点

要检查VM内存大小,请执行上述操作,并执行以下操作

在启动VM时使用Xmx和Xms标志,并故意将它们的值设置为低于可能需要的值,并密切关注OutOfMemoryError。

如果发生OutOfMemoryError,这意味着您超过了最大VM大小。确定原因并开始调整对象创建。

希望它有所帮助......


2

除了减少创建对象的数量并尝试使对象短暂存活外,您对内存没有太多可以做的。但是,为了获得最佳性能,Java仍将使用其允许的所有内存。


2
人们为了最小化Java中的内存利用率采取了哪些措施?
他们会查看小型基准测试而不是如何处理大数组的微型测试。
你可以尝试将Java的引用(即使在64位JVM上也使用4字节)与C ++共享指针(在64位进程上可使用48字节)进行比较,并得出一些结论,这些结论在实际程序中可能没有用处。
我更关注内存而不是性能,因为除了“编写更好的程序”和“正确调整JDK中的内存”之外,我想不到任何更好的方法。
通常您只需要使用内存分析器。这将有助于您最小化Java中的内存消耗。
我发现在大多数情况下,这种保存每个字节的痴迷已经过时了。在PC上,一字节的内存成本约为5e-7美分。或者大约2e-6秒的时间。这些时间可能会累积,但如果您仅保存100 KB,则可能不值得更改任何代码来执行此操作,如果要保存1 GB,则可能值得花费几个小时。即使您确实节省了1 GB的内存,该内存也是可重复使用的,但您的时间则不是。
如果内存是主要限制条件,那么您需要Java的原因是什么?
我同意这一点,如果您有一个几MB的设备,例如小于Android手机,则C将是您的最佳选择。如果您拥有至少智能手机容量的设备,则Java可能适合您的需求。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接