我习惯于避免局部变量 - 我做得对吗?

  • 本文关键字:习惯于 局部变量 java
  • 更新时间 :
  • 英文 :


我刚刚意识到,当我用Java编程时,我会避免局部变量,比如瘟疫,如果我真的必须用小写"L"作为成员的前缀,并有一个重置该对象的方法(如果对象是我的,我通常有一个名为init的私有方法或构造函数调用的东西)

我刚刚意识到这在很多方面都很丑陋。我做得对吗?

C++程序员会确切地知道我的意思,没有离开函数范围的局部会自动为我们销毁(如果它确实离开了函数范围,请使用指针,等等)

发生这种情况时的模式

我发现,每当我将适配器适配到函数参数并通过该适配器与之交互时,都是在我使用它的时候。

我还倾向于让适配器维护它使用的任何对象的池(最多一定数量)

当我想使用需要"new"进行初始化但仅在方法中的数据类型时,也会发生这种情况。

代码通常是一些主循环的一部分,否则也没关系,显然(这不是一次性的)

GC Collection amount:
Amount (Mb):  |   30|   60|   90|  120|  150|  180|  210|  240|  270|  300|  330|  360|
--------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
With pattern  |## (14)
without       |################################################################### (350)

该程序通过了单元测试,显示了平均GC量。两者的标准偏差均小于5。

这感觉好像在某种程度上与飞轮模式有关。。。

没有此代码,因为:

它可以以多种方式表现出来!例如,如果您有一个ComplexNumber类,如果您只是根据需要创建它们,您将生成大量垃圾,如果您拥有任何类型的vectormatrix类,也是如此。

另一个区域是涉及某种图形的任何内容,这些图形被仔细遍历以生成另一个结构,如场景图、关键路径,甚至是表示当前目录的堆栈。

基本上,如果你在一个经常被调用的方法中有"new"要分配给局部变量,你会发现这一点。

以上使用的样品

它来自我写的一个程序,教人们关于有限状态自动机和其他状态机(马尔可夫链等),我注意到严重的ram使用,并决定进行调查。

与其他语言的比较

显然C++没有这个问题。但你也不会很高兴知道Python。Python的引用计数意味着(如果你没有任何cricles),在方法结束的那一刻,东西就被删除了,实际上有一个元方法,你可以可靠地将其用作析构函数(如果你有足够的纪律,不会从方法中泄露它)

我不是第一个遇到这个问题的人,看到类似的问题表明没有解决方案,但我不敢相信以前从未遇到过这种情况!

关于我

我从C++和Python(都喜欢它们!)到Java,我在Java方面"经验丰富",因为我可以读/写有效的东西,它遵循了一个很好的设计哲学等等,但我倾向于非常注意性能和资源。我从恐慌中解脱出来,我是一个彻头彻尾的恐慌妓女。

如何不进行池化

假设您有一个GroupElement类,它表示代数群的一个成员,我们将使用加法表示法。

假设g.add(h)返回一个新元素,如果你多次这样做,你就会有很多元素。如果你有:

 GroupElement f = new GroupElement(0); //identity
 g.add(f,h); 

其中:

add的第一个参数是放置结果的位置,我们不生成垃圾。

不遵循上述内容的人

你应该知道复数是什么?假设一个复数有一个名为add的方法,它接受一个复数并返回一个新的复数。如果你做了很多次a=b.add(c);,你会得到很多减去1的垃圾复数。

如果你有inplaceAdd(ComplexNumber target, ComplexNumber value),说在哪里:

target.real = value.real+real;
target.im = value.im+im;

如果执行以下操作,则不会创建垃圾:b.inplaceAdd(a,c),其操作与上面的a=b.add(c) 相同

BTW add可以做到:return new ComplexNumber(real+value.real,im+value.im)——明白我现在的意思了吗?

示例的实现(说真的,伙计们,你们怎么不明白!)

public class ComplexNumber {
    private double real;
    private double im;
    public ComplexNumber(double r, double i) {
        real = r;
        im = i;
    }
    public ComplexNumber add(ComplexNumber value) {
        return new ComplexNumber(real + value.real, im + value.im);
    }
    public void inplaceAdd(ComplexNumber target, ComplexNumber value) {
        target.real = real + value.real;
        target.im = im + value.im;
    }
}

例如,如果您有一个ComplexNumber类,如果您只是根据需要创建它们,您将生成大量垃圾,如果您拥有任何类型的vectormatrix类,也是如此。

请记住,垃圾是免费的;垃圾收集的成本由必须遍历的垃圾决定。(我的意思是,VM规范实际上并没有具体说明GC必须如何实现,但主要的GC都是这样工作的。)这是有意为之:显然,Java实现不能使用引用计数没有技术原因;只是它被认为不是很健壮/高效/可靠等。(在C++、Perl和Python中,引用计数为您提供了可预测析构函数的优势。Java不提供这一点;相反,它提供了finally块和try-资源。)

最新更新