深入理解Java虚拟机之Java内存区域
Java虚拟机在执行Java程序时,会将内存分为几个部分,包括 方法区、堆、虚拟机栈、本地方法栈、程序计数器。其中堆和方法区是线程共有的内存区域。 虚拟机栈,本地方法栈、程序技术器为线程私有的内存区域,这部们内存区域随线程启动而生,线程结束而销毁。
线程私有的区域:
程序技术器:
它是一块很小的内存空间,可以看作线程执行字节码的行数指示器。 每个线程都私有一个程序计数器,并且互不影响。该区域不会出现OutOfMemoryError错误
Java虚拟机栈:
也是一块线程私有的内存区域,主要描述的是Java方法执行的内存模型。 每一个方法运行时会在虚拟机栈上创建一个栈帧(也就是入栈),栈帧中存放有 局部变量表、操作栈帧、动态链接方法出口等信息。 再重点讲一下局部变量表。局部变量表中存放了各种基本数据类型、对象的引用和returnAdress类型。我们经常说的对象引用就放在栈帧里,对象实例在堆中(后面会提到)
本地方法栈(不重要)
与虚拟机栈类似,区别在于虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机使用到的Native方法服务,在hotPot虚拟机中,将这两个栈合二为一
线程共有的区域
堆
是虚拟机管理的内存中最大的一块,用于存放各种对象实例,也是垃圾收集器管理的重要区域,故被称为GC堆
方法区
用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。这里不得不提到一个经常说到的区域:常量池
常量池分为两种:静态常量池 和 运行时常量池
静态常量池 即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。这种常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:
- 类和接口的全限定名
- 字段名称和描述符
- 方法名称和描述符
运行时常量池 是我们长说的常量池,在类加载后将class文件中的常量池载入到内存中,并保存在方法区中。
总结
虚拟机中的内存图示
虚拟机中对象的访问定位 图为通过直接指针访问对象
各区域存储的数据:
虚拟机栈: 存放局部变量(方法中的变量)、方法中的对象引用
堆: 存放对象实例
方法区:存放静态变量(类中的变量)、常量(各种常量池)、类信息