2014-01-10 202 views
6

我是一个交易的C++开发人员,但最近我一直在做点Java。我正在从事的这个项目是由一名开发人员完成的,而且我一直在寻找他正在围绕垃圾收集工作做些奇怪的事情。java垃圾收集和临时对象

案例和点,他实现了自己的字符串类,以避免GC

应用程序的这部分花费了大量的二进制文件格式,并将其出口到CSV放缓。这意味着为文件中的每一行建立一个字符串(百万)。为了避免这些临时字符串对象,他创建了一个字符串类,它只是重用了大量字节。

/** 
HACK 
    A Quick and Dirty string builder implementation optimized for GC. 
    Using String.format causes the application grind to a halt when 
    more than a couple of string operations are performed due to the number of 
    temporary objects allocated while formatting strings for drawing or logging.  
*/ 

这实际上有帮助吗?这真的需要吗?这比仅仅在循环外部声明一个String对象并将其设置在循环内部更好?

该应用程序还有一个哈希映射,其中包含值的双打。地图中的键是相当静态的,但值经常变化。 GC对双打怕他做了一个myDouble类作为值使用HashMap中

/** 
* This is a Mutable Double Wrapper class created to avoid GC issues 
* 
*/ 
public class MyDouble implements Serializable { 
    /** 
    * 
    */ 
    private static final long serialVersionUID = C.SERIAL_VERSION_UID; 
    public double d; 

    public MyDouble(double d) { 
     this.d = d; 
    } 
} 

这是疯了,完全没有必要的,对吧?

+2

为什么不用替代方法测试它,看看它是否有所作为?根据写入时间的不同,很可能JVM自那时以来已经有了很大的改进,并且代码已不再需要,但仍然完全有可能大幅超越标准内存分配器,因为它必须是标准的,并且自己的代码,你可以专门为你的场景编写它。 – Dukeling

+0

明智的意思是否落后于基准?如果没有,请自己想一些,并将信誉评分停靠几分。现在您可以量化更改的影响,并可以在不会不当影响性能的情况下开始简化代码。 – delnan

+2

回答你的第一个问题:是的,它*可以*帮助,但是看起来他已经在这里重新发明了轮子。现在我们使用'StringBuilder'类,它基本上对char缓冲区做了同样的事情并允许可变长的字符串。要回答第二个问题:不,在循环外部创建字符串引用并将其设置在循环内部仍然会创建一大堆字符串。在java中字符串文字是一种“特殊情况”。如果你的应用程序创建了许多独特的小字符串,或者附加了很多(我怀疑是这种情况),GC可能非常忙碌。 – CodeChimp

回答

3

确实,字符串连接可能是Java中的瓶颈,因为String是不可变的。这意味着每个级联会创建一个新的String,除非以前创建的匹配String因此位于字符串池中(请参阅string interning)。无论哪种方式,它肯定会导致问题。

但是,您的前任不是第一个遇到过这个问题的人,并且处理需要连接Java中的许多String的标准方法是使用StringBuilder

double(或任何基本事项)被用作局部变量时,它会一直保留在堆栈上,它占用的内存会随着堆栈帧一起释放(不确定它们是否受到GC或采用JVM在运行时关心)。但是,如果double是对象上的字段,它将存储在堆上,并在收集包含它的对象时收集。

没有看到如何使用double值,很难说,但很可能使用Map增加了GC负载。

总之,是的,这是肯定的,正如你所说的'疯狂和完全没有必要'。这些过早的优化只会使代码复杂化,使其更容易出现错误,并使日后的维护变得更加困难。黄金法则实际上应该始终如一,构建最简单的工作,分析并优化。

+0

感谢您对StringBuilder的建议 – Taz