java - 为多个值创建不同的变量vs 1个变量? [关闭]

问题描述 投票:-2回答:2

我有一些代码,如:

String country = null;
country = getEuropeanCountry(); //Germany
//after few lines of code
country = getAsianCountry(); //Japan
//after few more lines
country = getNorthAmericanCountry(); //Canada
/*and the code follows by assigning a different country value to the same variable "country"*/

我的大多数代码都有这种用法。

出于某种原因,我的应用程序抛出"Error java.lang.OutOfMemoryError: GC overhead limit exceeded"。所以我尝试使用VM参数:-XX:-UseGCOverheadLimit然后我的应用程序成功运行但我注意到它消耗更多内存(我必须将-Xmx设置为5g或6g;否则我得到:内存不足错误)。

我检查了我的应用程序,没有内存泄漏。但是我的大部分代码都有类似于上面发布的代码。

任何人都可以告诉我,如果我将上述代码重构为:

String europeanCountry = getEuropeanCountry(); //Germany
//after few lines of code
String asianCountry = getAsianCountry(); //Japan
//after few more lines
String northAmericanCountry = getNorthAmericanCountry(); //Canada
/*and the code follows by assigning a different country value to a different String variable*/

我不能使用收藏品。我的意思是,一般来说,哪种方式更好地有效地使用堆空间和垃圾收集器?

java memory-management
2个回答
1
投票

对于“我的意思是,一般来说,哪种方式更好地有效地使用堆空间和垃圾收集器?”

让我们看一下String实现,例如jdk8 https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/String.java

public final class String

    implements java.io.Serializable,  Comparable<String>, CharSequence {

    /** The value is used for character storage. */

    private final char value[];

所以它是一个最终的字符数组 - 它无法重新分配或更改。因此它在您的方法中在堆上生成,并且永远不会更改 - 仅生成引用(名称)。

为了不犯错误,让我们看一下String的构造函数(做smth。就像例如。“newString = new String(otherString)”:

public String(String original) {

    this.value = original.value;

    this.hash = original.hash;

}

同样在这种情况下,堆上没有分配额外的空间 - 它在堆上保持相同的单个最终char数组。

所以你可以为引用分配一个新的String。(给它一个额外的名字)。但它总是在您的方法中生成相同的唯一String,并且没有分配堆上的新空间。

因此,在第一个缩小范围内比较两种方法:

String europeanCountry = getEuropeanCountry();
String asianCountry = getAsianCountry();

String country = null;
country = getEuropeanCountry();
country = getAsianCountry();

两者都将在堆上正式创建相同数量的字符串,因为String总是在相同的方法中生成。变量只是对它的引用。

唯一的区别是在第二种情况下使用允许正式地将String更早地进行垃圾收集(在通过重用变量来删除对它的引用的那一刻)。

因此,使用第二种方法(重用),您可以在可接受的时间内生成更小的内存占用。

我在第一次缩小时说,因为只有在没有其他对String的引用且没有优化的情况下才会这样 - 所以如果不存在其他引用并且不会进行优化,则上述情况就是如此。

但是,在上面的代码中,变量不会退出范围,也不会使用。编译器将检测到这一点,根本不会分配任何变量。根据方法的不同,它们可能会被内联,也不会被调用。那么你所说的方法看起来有什么不同。根据它们的复杂程度,可以分配堆上的空间。

反过来说:如果您使用变量并且运行时检测到您可能会再次为同一个值调用该方法,则该值将保留在堆上并且即使没有正式的无引用也不会释放它并且它可能正式成为垃圾收集 - 所以该分配再次没有区别,但方法的调用。

还有一些观察:如果这些方法不只生成字符串,而是从某个地方(容器)中提取它们,或者将它们存储在某个地方,那么其他引用就是保存(并且)分配了空间的引用,并且你的分配使得关于堆没有任何区别:它与堆上的最终char数组相同。

考虑到这一点,您面临的问题很可能不是字符串的分配,而是代码的设计。它必须是一个更复杂的场景,其中引用保持更长时间。

到目前为止你的问题。

对于你的问题,我会看出来:

  • 用于容器
  • 生成变量的地方
  • 经常使用。这就是为很多不同的值非常频繁地调用这些方法,因为在这种情况下,它们被保存在内存中以便进行下一个假定的调用。
  • 对于不容易遵循数据流的代码。编译器通过分析流程进行优化。如果你不能遵循,编译器更有可能不能在其他部分中。

0
投票

假设显示的代码行来自单一方法(如果不是这样,请告诉我),至少有3个问题我可以用代码指出:

  1. 看来方法尺寸太大了。喜欢编写尽可能简洁的方法,只做“一件事”并做得好。
  2. 太多的状态变化。在第一个示例中,您将变量“country”设置为3个不同的方法返回值。
  3. 考虑使用polymorphism,而不是以if-else方式重复代码来获取国家

最后,还不清楚国家价值观如何用于方法。

© www.soinside.com 2019 - 2024. All rights reserved.