String和char的源码

String:源码如下,由一个char的数组组成。

1、该对象是放在常量池的,

2、对象内容不可变(不是绝对,通过反射可以修改),所有的修改内容操作,,都是new一个新的String对象返回。

3、Sting s = "hello";字符串放到常量池,太多放不下的时候就GC那些没有引用的。因为等价于String s = new String("hello").intern();(这个说法待定!!!)

4、String s = new String("hello");不会放到常量池,同理:String s = "hello"+1;在源码中重新new了一个字符串,并没有涉及intern()操作,所以"hello"会放入但"hello1"不会放到常量池。(只有通过String s = "hello";或者调用intern(),才会放入常量池。)所以for循环拼接时,其实是在内存中不断开辟空间存储新的字符串,浪费时间和内存空间。

5、intern()方法,是将当前字符串放到常量池,如果常量池已存在相同字符串则返回已存在的字符串引用,如果不存在则将当前字符串拷贝一份放到常量池,并返回拷贝的字符串引用(注意:java6以及之前版本常量池是放在永久代的,java7之后常量池也在堆内存里)。

网上的总结:

1)不要在Java 6及以前的版本使用String.intern()将字符串放入常量池,因为这是的字符串常量池是存储在固定大小的内存区(PermGen)

2)Java 7和8中将字符串常量池存储在堆内存中。

3)Java 7和8中可以通过JVM参数-XX:StringTableSize来控制字符串常量池的大小。

4)-XX:StringTableSize的默认值在Java 7中是1009,在Java 8中大概是25~50K

5)在多线程情况下可以随意使用Stirng.intern()方法。8个写线程只比1个写线程的负载多了17%,1个写7个读线程只比一个线程的负载多了9%

6)字符串常量池不是线程隔离的

7)虽然Java 7+对String.intern()做了很多优化,但是它还是花费CPU资源。在简单的例子中没有调用String.intern()方法的程序比调用了的程序要快3.5倍。所以不需要对所有的字符串调用String.intern()方法,只需要对经常被使用的字符串(例如:省、市等)调用String.intern()方法加入常量池。

 

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[];
    private int hash; // Default to 0
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
    public native String intern();
}

 

 其中,在虚拟机规范所说的那样,JVM中的内存分为5个虚拟的区域:堆、方法区和持久代(非堆)、JVM栈、本地栈、PC寄存器

Java8的JVM持久代 - 何去何从?

java8以后,持久代已经被彻底删除了,取代它的是另一个内存区域也被称为元空间。

元空间:

1、它是本地堆内存中的一部分

2、它可以通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize来进行调整

3、当到达XX:MetaspaceSize所指定的阈值后会开始进行清理该区域

4、如果本地空间的内存用尽了会收到java.lang.OutOfMemoryError: Metadata space的错误信息。

5、和持久代相关的JVM参数-XX:PermSize及-XX:MaxPermSize将会被忽略掉。 

 

 

char:包装类为Character

猜你喜欢

转载自1181731633.iteye.com/blog/2356394