深入理解Java虚拟机之Java内存区域

        Java虚拟机在执行Java程序时,会将内存分为几个部分,包括 方法区、堆、虚拟机栈、本地方法栈、程序计数器。其中堆和方法区是线程共有的内存区域。  虚拟机栈,本地方法栈、程序技术器为线程私有的内存区域,这部们内存区域随线程启动而生,线程结束而销毁。

   线程私有的区域:

       程序技术器:

           它是一块很小的内存空间,可以看作线程执行字节码的行数指示器。 每个线程都私有一个程序计数器,并且互不影响。该区域不会出现OutOfMemoryError错误

      Java虚拟机栈:

          也是一块线程私有的内存区域,主要描述的是Java方法执行的内存模型。  每一个方法运行时会在虚拟机栈上创建一个栈帧(也就是入栈),栈帧中存放有 局部变量表、操作栈帧、动态链接方法出口等信息。 再重点讲一下局部变量表。局部变量表中存放了各种基本数据类型、对象的引用和returnAdress类型。我们经常说的对象引用就放在栈帧里,对象实例在堆中(后面会提到)        

       本地方法栈(不重要)

             与虚拟机栈类似,区别在于虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机使用到的Native方法服务,在hotPot虚拟机中,将这两个栈合二为一

     线程共有的区域

          堆

                 是虚拟机管理的内存中最大的一块,用于存放各种对象实例,也是垃圾收集器管理的重要区域,故被称为GC堆

          方法区

                  用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。这里不得不提到一个经常说到的区域:常量池  

       常量池分为两种:静态常量池 和 运行时常量池 

        静态常量池 即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。这种常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:

  • 类和接口的全限定名
  • 字段名称和描述符
  • 方法名称和描述符

        运行时常量池 是我们长说的常量池,在类加载后将class文件中的常量池载入到内存中,并保存在方法区中。

总结

     虚拟机中的内存图示   

深入理解Java虚拟机之Java内存区域

虚拟机中对象的访问定位   图为通过直接指针访问对象

深入理解Java虚拟机之Java内存区域

各区域存储的数据:

   虚拟机栈: 存放局部变量(方法中的变量)、方法中的对象引用

   堆: 存放对象实例

   方法区:存放静态变量(类中的变量)、常量(各种常量池)、类信息