编程时尽量少使用堆空间的注意事项

时间:2011-08-17 04:44:19

标签: java memory-management heap core

这些占用堆中的空间

字符串:明智地使用String,尝试使用局部变量,确保没有没有引用的字符串并尝试使用StringBuffer或StringBuilder

静态:明智地使用静态

实例变量:尝试尽可能在本地声明变量

对象:尽可能重用

如果到目前为止,请纠正我错误...还建议我在Java编程时可以采取更多预防措施来减少堆空间的使用

5 个答案:

答案 0 :(得分:3)

您需要更加具体地了解您要实现的目标。有两个目标(在某些情况下)是矛盾的:

  • 最小化分配的对象数量,从而减少GC运行的次数,
  • 最大限度地减少用于活动对象的堆空间量,从而最大限度地减少应用程序的“占用空间”。
  

静态:明智地使用静态

这是毫无意义的建议,除非你说“明智的用处”。

  

字符串:明智地使用String,尝试用作局部变量,确保没有没有引用的字符串并尝试使用StringBuffer或StringBuilder

  • 明智的使用是毫无意义的建议;往上看。
  • 确保没有没有引用的字符串是没有意义的,因为每个字符串都有一个引用。
  • 尝试使用局部变量很有用,但并不总是适用。有时使用静态或实例变量可以减少创建新字符串的次数。有时将中间字符串分配给局部变量可能会延长其使用寿命。
  • 您不应该使用StringBuffer进行字符串汇编。
  • 在很多情况下,在字符串汇编中使用StringBuilder没有帮助,只会使代码更难阅读。通常,只有在不能在一个表达式中执行字符串汇编时才应使用StringBuilder。
  

实例变量:尝试尽可能在本地声明变量

这通常是合理的建议,但需要与其他事物保持平衡。

  

对象:尽可能重用

这是不好的建议。

重用“尽可能”意味着对象池,并且对象池倾向于使用更多堆空间,而不是只丢弃对象并让GC回收它。只有在最小化对象创建速率至关重要时才应使用对象池。即使这样,你也需要非常小心避免:

  • 通过不将对象返回池中来泄漏对象
  • 从池中发出“脏”对象
  • 由于额外的复杂性而导致错误,
  • 浪费内存(例如,在池数据结构和池中的空闲对象上),从而使GC更频繁地运行。

答案 1 :(得分:2)

以下几点可以帮助提高应用程序的内存利用率如果明智地使用。但是请注意它们并不是普遍适用的,如果你不明白你在做什么,你会得到一个糟糕的结果....一个更复杂的程序,几乎没有任何内存使用的改进。

仔细设计/选择您的收集数据结构

许多标准的Java集合类型都非常需要内存。例如,ArrayList<Integer>包含2个要开始的对象,以及每个数组元素的额外对象(取决于元素的创建方式......)。此外,ArrayList的后备阵列可能比它需要的大。相比之下,int[]只包含一个对象,每个元素只使用一个32位字。

(可以对更复杂的数据结构进行类似的比较,特别是当基类型是基本类型时。有第三方库实现这种东西;例如GNU Trove库。)

很明显,如果仔细设计数据结构,可以使用更少的内存和更少的对象来表示它们。

然而,另一方面,这往往会使您的应用程序更复杂,更难维护。例如:

  • 使用int[]代替ArrayList<Integer>会导致更多实施细节曝光,并增加耦合。

  • 使用数组来表示变量或不确定大小的列表很棘手。

  • 许多API旨在采用ListCollection参数而不是数组参数。因此,您更有可能必须开发自己的自定义非集合版本的库代码。

  • 泛型和数组不能很好地混合。

总之,虽然您可以节省堆空间,但可能最终以其他方式付款。

使用可变类

StringBigInteger等类的实例在设计上是不可变的。这简化了计算模型,但这意味着“改变”某些事情涉及创建新对象。您通常可以通过以下方式减少内存使用量:

  • 使用类型的可变版本;例如使用StringBuilder / StringBuffer代替String

  • 使您自己的应用程序数据类可变而不是不可变。

再次,有一个反面。可变数据结构可能导致更复杂;例如如果您的应用程序是多线程的,或者您需要能够撤消回溯或某些步骤失败的事情。这使您的应用程序更加复杂。在某些情况下,唯一可行的解​​决方案是复制数据结构,从而使用更多内存。

总之,虽然您可以节省堆空间,但可能最终以其他方式付款。你甚至可能最终都不会节省记忆。

答案 2 :(得分:0)

这很不错。要注意的另一件事是正确关闭你的缓冲区类型对象,我的意思是套接字,文件阅读器等等......确保你将它们包装在最后,最后你记得在哪里刷新(如果需要)和关闭连接/缓冲区。这可以避免因为底层连接仍然处于活动状态而保留杂散资源。

答案 3 :(得分:0)

同样关于字符串的主题,在从文件或数据库中读取时总是intern(),所以你最终不会有重复的字符数组。

答案 4 :(得分:-1)

首先:测量哪些对象占用最多的堆空间:jmap -histo:live

然后尝试减少前五个班级。而已。再次测量。重复,直到你满意为止。

如果其中一个候选者是HashMapHashSetConcurrentHashMap:这些类会尽可能地浪费堆内存。为他们使用节省内存的替代品。