根据著名本书深入浅出Java页面661:
" Garbage Collector doesn't go inside String pool.
"
在阅读了关于SO的类似问题后,我发现了如下混合答案:
我的问题是:
如何在Java 6及之前收集字符串文字垃圾?
因为在Java 7中,将在堆上创建字符串文字,与Java 6相比,Java 7中字符串文字的垃圾收集将如何不同?
据我所知,如果使用文字初始化String,则会在String Pool中分配一个空格,如果使用新的Keyword初始化,则会创建String的对象.但我对下面写的案例感到困惑.
我的问题是,如果使用new关键字创建String,然后使用文字更新值?
例如
String s = new String("Value1"); -- Creates a new object in heap space
Run Code Online (Sandbox Code Playgroud)
那么如果写下面的语句怎么办呢.
s = "value2";
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,
1它是否会在字符串池中创建字符串文字,还是会更新该对象的值?
2如果它在字符串池中创建一个新文字,那么当前存在的对象会发生什么?是否会被破坏,或者它会在那里被调用垃圾收集器.
这是一个小字符串,如果字符串是成千上万的字符,那么我只是担心它使用的空间.所以我的关键问题是空间.
在分配文字后,它会立即从堆中释放空间吗?
任何人都可以解释从第一个语句到第二个语句的值是什么,以及内存区域(堆和字符串池)会发生什么.
我将普通密码作为字符串存储在内存中时出现问题.根据该参考文献,由于字符串是不可变的,因此存在使用字符串数据类型存储在内存中的敏感数据的漏洞.
https://www.geeksforgeeks.org/use-char-array-string-storing-passwords-java/
我可以通过使字符串变量无效而不是使用char数组或字符串缓冲区/构建器来克服此安全问题.
例如:String password ="password"; password = null;
我见过几个类似的问题,但他们的答案并没有真正回答我的问题。
当我们编辑字符串并创建新字符串时,旧字符串去了哪里。
String s1 = "Hello"
s1 += "World"
Run Code Online (Sandbox Code Playgroud)
我们有一个字符串 Hello,但随后创建了一个新字符串,它是 HelloWorld。
字符串 Hello 是否仍在字符串池中(我猜不是,因为我们失去了对它的引用)。垃圾收集器会销毁它吗?
如果我们创建一个新字符串并使用 intern 方法会怎样?该字符串将从池中取出吗?
String s1 = "Hello";
s1 += "World";
String s2 = "Hello";
Run Code Online (Sandbox Code Playgroud)
在这个话题中,Stephen C 说
如果字符串变得无法访问,它们将被垃圾收集
但我做了这样的事:
String s1 = "Hello";
System.out.println(System.identityHashCode(s1));
s1 += "World";
System.gc();
String s2 = "Hello";
System.out.println(System.identityHashCode(s2));
Run Code Online (Sandbox Code Playgroud)
它打印了相同的身份哈希码,尽管我丢失了对“Hello”字符串的引用,并且新的应该打印了另一个身份哈希码。
他还表示
这意味着只要该方法可以执行,该字符串就可以访问。
但我做了一个与上面类似的实验,该方法创建了一个字符串,然后在另一种方法中,我创建了相同的字符串(在使用 System.gc 之前),并打印出相同的身份哈希代码。
如果我丢失了对这两种情况的引用,为什么 GC 不会销毁它们?
我相信当我new String
在整个应用程序中的各个地方打电话时会产生这种垃圾.如何在不创建新对象的情况下"创建"字符串?
这种垃圾敏感的原因是因为我的应用程序无法创建垃圾,因为我们需要使用默认的Java GC接近实时运行.
// you can see I use the same chars array
public String getB37String() {
long l = getLong();
int i = 0;
while (l != 0L) {
long l1 = l;
l /= 37L;
chars[11 - i++] = validChars[(int) (l1 - l * 37L)];
}
return new String(chars, 12 - i, i);
}
Run Code Online (Sandbox Code Playgroud)
例如StringBuilder.toString()
,使用new String
下面使用的.
// and you can see that I use the same builder
public String …
Run Code Online (Sandbox Code Playgroud) 在这里查看一些Fortify的发现,它告诉我不要对敏感数据使用字符串数据类型,因为它们可能会在内存中停留太长时间.如果存在无关的内存攻击,例如Heartbleed,则会暴露用户的数据.
如果我在使用后将字符串var设置为null,那么该内存位置是否实际被清除,或者是为存储null而创建的var的副本?
谢谢
我知道Java中的String变量是不可变的,因此不能更改.
String myString = "Hello.";
myString += " ";
myString += "My name is Kevin";
Run Code Online (Sandbox Code Playgroud)
每次我们"添加"某些东西时String()
,我们都在有效地创建一个新的String()
,但它与它被连接的字符串具有相同的名称.这是否意味着内存中有多个引用变量"myString"?