大家推荐个靠谱的公众号程序员探索之路,大家一起加油
程序计数器:
它是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.各种虚拟机实现的方式可能不一样.字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,
循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成.
java vm的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,一个处理器在任何时刻都只能执行一个线程中的指令.所以线程切换后,每条线程都有自己的程序计数器,线程之间互补影响,
独立存储,所以称为线程私有的.
虚拟机栈
虚拟机栈的生命周期与线程相同.虚拟机栈描述的是java方法执行的内存模型:每个方法在执行时都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息.每一个方法从调用直至执行完成
的过程,就对应着一个栈帧在虚拟机栈中从进栈到出栈的过程.当线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈无法申请到足够的空间时将抛出OutOfMemoryError
(也就是OOM)
本地方法栈
本地方法栈和虚拟机栈功能是一样的,只是虚拟机栈是为java方法(也就是字节码)服务的,而本地方法栈是为native方法服务的.Sun HotSpot虚拟机之家吧虚拟机栈和本地方法栈合二为一.
java堆
java堆是被所有线程共享的一块区域,在虚拟机启动时创建.此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存.在虚拟机规范中描述是:所有的对象实例数组都要在堆上分配,
但是随着逃逸分析,标量替换优化技术,所有的对象实例数组都要在堆上分配变得不是那么绝对.
方法区
方法区用于存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,它还有一个别名(Non-Heap),jdk1.7之前这块还叫做永久代,1.7就开始去永久代
运行时常量池
运行时常量池在1.6时实在方法区中,1.7及以后就放在了堆中
这里讲一个知识点
String.intern()方法是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用.
String A="ABC";
String B=new String("ABC");
这两种创建字符串有什么区别,String A="ABC"; 会在常量池中找是否有相等的字符串,如果没有的话,在常量池中开辟一块儿内存空间,把地址付给栈指针,
如果已经有了"ABC"的内存,直接把地址赋给栈指针;
String B=new String("ABC");"a"这个String对象再次构造一个String对象;在堆中从新new一块儿内存,把指针赋给B
public static void main(String[] args) {
String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);
}
这块代码在1.6中 输出false, false 在1.7中输出true,false
1.6intern方法会把首次遇到的字符串示例复制到常量池中,返回的是常量池中的引用
1.7intern方法会把首次遇到的字符串记录下来,所以 第一个会输出true,但是java不是第一次 所以str2.intern()返回的是常量池中的引用,str2是new 出来的 toString()方法调用的是new String()