Java虚拟机运行原理





理解java虚拟机 java虚拟机的运行机制_常量池




一、虚拟机栈(线程私有)


       概念:虚拟机栈简称栈,存放着基本类型的变量数据和对象的引用,但对象本身不存在栈中,而存放在堆中或者常量池中。



       原理:①栈的分配:每个主线程分配一个栈;


                  ②栈与寄存器:Java虚拟机是基于栈索引,而Dalvik虚拟机是基于寄存器索引的;(Java程序其中也用到寄存器,而且在系统运行


                                           时分配好,但是不由虚拟机管理)。


                  ③栈帧:栈中存放的是栈帧,用与存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直到执行完成的过程,就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。局部变量表存放了编译期可知的各种基本数据类型、对象引用(可能是对象的起始地址引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。long和double类型数据会占用2个局部变量空间,其余数据只占用1个。局部变量表所需的内存空间在编译期间就完成分配。补充:句柄是整个Windows编程的基础。一个句柄是指使用的一个唯一的整数值,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类对象中的不同的实例。



       过程:变量通过指向引用,而引用又通过引用中的堆地址指向堆中对应的对象,从而查找对应对象的对应信息。


       



二、本地栈(线程私有)


       概念:本地栈也是栈的一种,只是它的引用仅仅指向本地系统的API。


       原理:同虚拟机栈一样。


       过程:同虚拟机栈一样。


       区别:区别在于栈中的引用仅仅指向本地系统的API。




三、堆(线程共享)


       概念:存放着所有new的对象。(运行期间才能确定的)


       原理:引用的作用是指向堆中的对象,当引用消失了,则堆中的相应对象也会被Java 垃圾回收机制回收。


       内存划分:①内存回收角度:采用的分代收集算法,所以堆还可以细分为新生代和老年代;再细分有Eden空间,From Survivor空间、


                                                     To Survivor空间等。


                        ②内存分配角度:线程共享的堆中可能划分出多个线程私有的分配缓冲区。



四、方法区(线程共享)


       概念:存放加载的类信息(class)、常量、静态变量(常量池中)、即时编译器编译后的代码等数据。(编译期间就能确定)


       内存回收:这个区域的内存回收目标最主要是针对常量池的回收和对类型的卸载。



五、常量池(线程共享)


       概念:存放字符串常量(static+final)和基本类型常量(static+final 或 const)(编译期间就能确定)


       原理:具有动态性:并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,如String类的intern()方法。



六、程序计数器(线程私有)


        概念:当前线程所执行的字节码的行号指示器。


        原理:由于Java虚拟机的多线程是通过线程之间轮流切换,每次切换通过字节码解析器进行解析。字节码解析器的作用就是通过改变这个计数器选取下一条需要执行的字节码指令进行解析的,每次切换线程程序计数器就会保存当前执行到的位置。



 虚拟机运行机制简易实例:


package com.itaem;

public class TestService {

	 public static void main(String[] args){
         /*
          *     只在堆中创建对象
          */
         String str = new String("哈哈") ;  
         /*
          *     常量池没有"哈哈"对象,在常量池创建对象,并且拷贝该对象到堆中
          *       原理:从常量池找到则直接指向常量池对应对象。常量池没有则在常量池创建对象,并且拷贝该对象到堆中。
          */
         String str1 = "哈哈" ;
         System.out.println(str == str1) ;  //false
	 }
}