1、堆区
- 存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
- jvm只有一个heap区,被所有线程共享,不存放基本类型和对象引用,只存放对象本身
堆的优劣势:
- 堆的优势是可以动态的分配内存大小,生存期也不必事先告诉编译器,java的垃圾收集器会自动收取这些不再使用的数据
缺点是:
- 由于要在运行时动态分配内存,存取速度慢
2、栈区
- 每一个线程包含一个stack区,只保存基本数据类型的对象和自定义对象的引用(不是对象),对象都存放在共享heap中
- 每个栈中的数据(基本数据类型和对象引用)都是私有的,其他栈不能访问
栈分为3部分:
- 基本类型变量区
- 执行环境上下文
- 操作指令区(存放操作指令)
栈的优势劣势:
- 存取速度比堆要快,仅次于直接位于CPU的寄存器
- 但必须确定的是存在stack中的数据大小与生存期必须是确定的,缺乏灵活性
- 单个stack的数据可以共享
- stack:是一个先进后出的数据结构,通常保存方法中的参数,局部变量
- 在java中,所有基本类型和引用类型都在stack中储存,栈中数据的生存空间一般在当前scopes内
3、方法区
- 又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量
- 方法区中包含的都是在程序中永远的唯一的元素
4、Java中不同的存储数据的地方:
寄存器(register)
-
最快的存储区,因为它位于不同于其他存储区的地方——处理器内部
-
但是寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配
-
你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象
堆栈(stack)
- 位于通用RAM中,但通过它的“堆栈指针”可以从处理器哪里获得支持
- 堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些 内存
- 一种快速有效的分配存储方法,仅次于寄存器
堆(heap)
- 通用性的内存池(也存在于RAM中),用于存放所以的JAVA对象
-
好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间
-
因此,在堆里分配存储有很大的灵活性
5、JVM内存模型
大多数JVM将内存分配为:
- Method Area(方法区)
- Heap(堆)
- Program Counter Register(程序计数器)
- JAVA Method Stack(JAVA方法栈)
- Native Method Stack(本地方法栈)
6、Method Area(方法区)
- 线程共享,存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等等
- HotSpot虚拟机上开发部署人员更愿意成为“永久代”,Permanent Generation
类型信息
- 类型的全限定名
- 超类的全限定名
- 直接超接口的全限定名
- 类型标志(该类是类类型还是接口类型)
- 类的访问描述符(public、private、default、abstract、final、static)
类型的常量池
- 存放该类型所用到的常量的有序集合
- 包括直接常量(如字符串、整数、浮点数的常量)和对其他类型、字段、方法的符号引用
- 常量池中每一个保存的常量都有一个索引,就像数组中的字段一样
- 常量池中保存中所有类型使用到的类型、字段、方法的字符引用,所以它也是动态连接的主要对象(在动态链接中起到核心作用)
字段信息(该类声明的所有字段)
- 字段修饰符(public、protect、private、default)
- 字段的类型
- 字段名称
方法信息(包含类的所有方法,每个方法包含以下信息)
- 方法修饰符
- 方法返回类型
- 方法名
- 方法参数个数、类型、顺序等
- 方法字节码
- 操作数栈和该方法在栈帧中的局部变量区大小
- 异常表
类变量(静态变量)
- 该类所有对象共享的变量,即使没有任何实例对象时,也可以访问的类变量。它们与类进行绑定
指向类加载器的引用
- 每一个被JVM加载的类型,都保存这个类加载器的引用,类加载器动态链接时会用到
指向Class实例的引用
- 类加载的过程中,虚拟机会创建该类型的Class实例,方法区中必须保存对该对象的引用
- 通过Class.forName(String className)来查找获得该实例的引用,然后创建该类的对象
方法表
- 为了提高访问效率,JVM可能会对每个装载的非抽象类,都创建一个数组
- 数组的每个元素是实例可能调用的方法的直接引用,包括父类中继承过来的方法
- 这个表在抽象类或者接口中是没有的
运行时常量池(Runtime Constant Pool)
- Class文件中除了有类的版本、字段、方法、接口等描述信息外
- 还有一项信息是常量池,用于存放编译器生成的各种字面常量和符号引用
- 这部分内容被类加载后进入方法区的运行时常量池中存放
运行时常量池相对于Class文件常量池的另外一个特征具有动态性
- 可以在运行期间将新的常量放入池中(典型的如String类的intern()方法)
- 运行时常量池是把Class文件常量池加载进来,每个类有一个独立的
- 刚开始时运行的时候常量池里的链接都是符号链接(只用名字没有实体),跟在Class文件里的一样
- 边运行边把常量转换成直接链接