在查看在线代码示例时,我有时会通过使用new运算符将String常量赋值给String对象.
例如:
String s;
...
s = new String("Hello World");
Run Code Online (Sandbox Code Playgroud)
当然,这与之相比
s = "Hello World";
Run Code Online (Sandbox Code Playgroud)
我不熟悉这种语法,也不知道目的或效果是什么.由于String常量通常存储在常量池中,然后以JVM处理String常量的任何表示形式存在,甚至还会在堆上分配任何内容?
与其他平台一样,跟进这个问题似乎合乎逻辑:Java中常见的非明显错误是什么?似乎他们应该工作的事情,但不是.
我不会给出如何构建答案的指导,或者什么"太容易"被认为是一个问题,因为这就是投票的目的.
也可以看看:
我正在读取一个非常大的文件,并从每一行中提取一小部分文本.但是在操作结束时,我的内存很少.在读取文件后,垃圾收集器似乎无法释放内存.
我的问题是:有没有办法释放这段记忆?或者这是一个JVM错误?
我创建了一个SSCCE来证明这一点.它读取1 mb(由于16位编码而在Java中为2 mb)文件并从每行中提取一个字符(~4000行,因此应该是大约8 kb).在测试结束时,仍然使用了完整的2 mb!
最初的内存使用情况:
Allocated: 93847.55 kb
Free: 93357.23 kb
Run Code Online (Sandbox Code Playgroud)
读取文件后立即(在任何手动垃圾收集之前):
Allocated: 93847.55 kb
Free: 77613.45 kb (~16mb used)
Run Code Online (Sandbox Code Playgroud)
这是预料之中的,因为程序正在使用大量资源来读取文件.
然而,我垃圾收集,但不是所有的内存都被释放:
Allocated: 93847.55 kb
Free: 91214.78 kb (~2 mb used! That's the entire file!)
Run Code Online (Sandbox Code Playgroud)
我知道手动调用垃圾收集器不会给你任何保证(在某些情况下它是懒惰的).然而,这发生在我的大型应用程序中,其中文件几乎占用了所有可用内存,并且导致程序的其余部分尽管需要它而耗尽内存.这个例子证实了我怀疑从文件中读取的多余数据没有被释放.
以下是生成测试的SSCCE:
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws Throwable {
Runtime rt = Runtime.getRuntime();
double alloc = rt.totalMemory()/1000.0;
double free = rt.freeMemory()/1000.0;
System.out.printf("Allocated: %.2f kb\nFree: %.2f kb\n\n",alloc,free);
Scanner in = new Scanner(new File("my_file.txt"));
ArrayList<String> …Run Code Online (Sandbox Code Playgroud) 我读过文章和书籍,String s = new String("...");应该尽可能避免使用.我明白为什么会这样,但是使用String(String)构造函数有什么用处吗?我不认为有,也没有看到任何其他证据,但我想知道SO社区中是否有人知道有用.
确切重复: java中表达新字符串的目的是什么?
class StringTesting {
public static void main(String args[])
{
String str = "abcd";
String str1 = new String("abcd");
String str2 = str.substring(0,2);
String str3 = str.substring(0,2);
String str4 = str.substring(0,str.length());
String str5 = str1.substring(0,2);
String str6 = str1.substring(0,2);
String str7 = str1.substring(0,str1.length());
System.out.println(str2 == str3);
System.out.println(str == str4);
System.out.println(str5 == str6);
System.out.println(str1 == str7);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我在java 1.6.0_27上得到的输出:
false
true
false
true
Run Code Online (Sandbox Code Playgroud)
有人可以解释输出.我知道Java区分存储在堆中的String和存储在String"common pool"中的String(可以是interned).在内部,他们的表现如何不同.它是如何改变子串算法的.请在适当的地方引用书籍/文章/博客等.
根据这篇Go Data Structures文章,在Strings部分下,它指出采用一个字符串片段会将原始字符串保留在内存中.
"(另外,在Java和其他语言中有一个众所周知的问题,当你切割一个字符串来保存一小块时,对原始文件的引用会将整个原始字符串保留在内存中,即使只有少量仍然存在Go也有这个问题.我们尝试和拒绝的替代方案是使字符串切片如此昂贵 - 分配和副本 - 大多数程序都避免使用它.)"
所以如果我们有一个很长的字符串:
s := "Some very long string..."
Run Code Online (Sandbox Code Playgroud)
我们采取一小部分:
newS := s[5:9]
Run Code Online (Sandbox Code Playgroud)
在s我们发布之前,原件不会发布newS.考虑到这一点,如果我们需要newS长期保留,但是s为垃圾收集发布,采取什么方法?
我想也许这个:
newS := string([]byte(s[5:9]))
Run Code Online (Sandbox Code Playgroud)
但我不确定这是否真的有用,或者是否有更好的方法.
我是Java的新手,我对使用构造函数有一些疑问:
Map<String, Object> map = new HashMap<String, Object>();
map.put("one", new String("Hello"));//1
map.put("two", "world");//2
Run Code Online (Sandbox Code Playgroud)
哪个陈述更加糟糕?有什么区别?哪一个是最好的?
看看这个测试
String s1 = "1234";
String s2 = "123";
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
char[] value1 = (char[]) field.get(s1);
char[] value2 = (char[]) field.get(s2);
System.out.println(value1 == value2);
Run Code Online (Sandbox Code Playgroud)
它打印false,这意味着JVM为s1和s2保存两个不同的char数组.任何人都可以解释为什么s1和s2不能共享相同的char数组?似乎java.lang.String是为内容共享而设计的,不是吗?
注意:我不了解所有JVM.这是Oracle的Java HotSpot(TM)客户端VM 22.1-b02(JRE 1.7).
UPDATE
在另一方面,如果部分共享是罕见的(似乎这只是由String.substring创建字符串),那么为什么要把所有的字符串也有int count和int offset领域?这是8个无用的字节.这不仅是尺寸,也是创作速度.对象越大,初始化时间越长.这是一个测试
long t0 = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
new String("xxxxxxxxxxxxx");
}
System.out.println(System.currentTimeMillis() - t0);
Run Code Online (Sandbox Code Playgroud)
需要~200ms.如果我使用这个课程
class String2 {
char[] value;
String2(String2 s) {
value = s.value;
}
}
Run Code Online (Sandbox Code Playgroud)
大约需要140毫秒.
java ×7
string ×6
coding-style ×1
go ×1
map ×1
memory ×1
object ×1
performance ×1
slice ×1
substring ×1