在做一些面试题或者面试的时候,经常会碰到String s = new String("abc") 一共创建了几个对象这个问题,要先了解这个问题,首先我们得先知道jvm的内存。
在jdk1.8之前,jvm运行时数据区分布如下:其中方法区和堆内存是所有线程共享的,而程序计数器、虚拟机栈、本地方法栈是线程私有的。
其中对于方法区,大家常常称之为:“永久代(Permanent Generation)”,但是二者本质上并不相同。 仅仅是因为习惯使用说使用永久代来实现方法区而已,这样HotSpot的垃圾收集器就可以像管理Java堆一样管理这部分内存,能够省去专门为方法区变编写内存管理代码的工作。
1.程序计数器:它是一块较小的内存空间,可以看做是指向当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程回复等基础功能都需要依赖计数器来完成。
2.本地方法栈:调用系统底层资源。
3.方法区(数据区或共享区或共享数据区):存放全局变量,静态变量,字符串常量和方法。
4.栈:存放方法参数值和局部变量。
5.堆:存放对象 ,即所有需要通过new创建的。
补充:堆和栈效率比较
栈由系统自动分配释放,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便, 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。。
在jdk1.8之后,元数据区取代了永久代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存。
最后回来看 String s = new String("abc") 一个创建了几个对象?分别存放在上面地方?
一共创建了2个对象。一个存在方法区的字符串常量池中,存值;一个存放在存放在堆区,存放在对象的引用。(前提是 String Pool 中还没有 "abc" 字符串对象)。
- "abc" 属于字符串字面量,因此编译时期会在常量池中创建一个字符串对象,指向这个 "abc" 字符串字面量;
- 使用 new 的方式会在堆中创建一个字符串对象。 (字符串常量"abc"在编译期就已经确定放入常量池,而 Java 堆上的"abc"是在运行期初始化阶段才确定)。