一.JVM的基本结构
各自作用
1.类加载子系统:负责从文件系统或者网络中加载Class信息,加载的信息存放在一块称之为方法区的内存空间
2.方法区:存放类信息、常量信息、常量池信息、包括字符串字面量和数字常量等
3.java堆:在jvm启动时建立,它是java程序最主要的内存工作区域,几乎所有的对象实例都存放在堆中,堆空间是所有线程共享的
4.直接内存:java的nio库允许java程序使用直接内存,从而提高性能,通常直接内存速度会优于java堆。读写频繁的场合可能优先考虑使用
5.栈:每个jvm线程都有个私有的栈,一个线程的java栈在线程创建的时候会被创建,java栈中保存着局部变量、方法参数、同时java的方法调用、返回值等。
6.本地方法栈:本地方法栈和java栈很类似,有些jvm实现是把这两个区域合在一起的,最大的不同是本地方法栈是本地方调用的,jvm允许java直接调用本地方法(通常用C编写)
7.垃圾回收系统:垃圾回收系统是java的核心,也是必不可少的,java有一套直接进行垃圾清理的机制,开发人员无需手工清理
8.PC寄存器:存放当前执行环境的指针、程序计数器、操作栈指针、计算变量的指针等等
9.执行引擎:jvm的最核心组件,负责执行虚拟机的字节码,一般现先进行编译成机器码后执行
二.堆、栈、方法区的概念和联系
1.堆解决的是数据存储的问题,即数据怎么放、放在哪里
栈解决的是程序的运行问题,即程序如何执行,或者说如何处理数据
方法区则是辅助堆栈的快永久区(Perm),解决堆栈信息的产生,是先决条件
举个例子:
我们创建一个新对象User,那么User类的一些信息(类信息、静态信息都存放于方法区中)
而User类被实例化之后,会被存储在java堆中
当我们使用这个实例的时候,都是使用User对象的引用,如:User user = new User(); 这里的user引用就是存放在java栈中的
如下图所示
ps:其实,常见的引用和真实对象的关系有两种,如下图
sun公司的hotspot采用的是图b的做法,原因很简单,jvm里的堆是很经常GC的,很经常会发生对象的移动,对象一移动,对象的地址(指针)就会跟着变化。
如果采用的是图a的做法,就很经常需要改变对象的指针,但是采用b的做法就不需要
三.java的堆
根据垃圾回收机制不同,java堆有可能拥有不同的结果。最常见的就是将整个java堆分为新生代和老年代。其中新生代存放新生的对象或者年龄不大的对象,老年代则存放着老年对象。
新生代分为eden区、s0区、s1区,s0和s1也被称为from和to区域,他们是两块大小相等且可以互换角色的空间
绝大部分情况下,对象首先分配在eden区,在一次新生代回收后,如果对象还存活,则会进图s0或者s1区,之后没经过一次新生代回收,如果对象还存活则它的年龄就+1,当对象达到一定的年龄后,则进入老年代
新生代大小一般会设置整个堆空间的1/3到1/4左右,占比可以设置
默认情况下,经过15次GC还没被收集掉的新生代对象转到老年代,参数可设置;另外,如果有大对象(eden区无法装入)参数,对象也会直接进入老年代。也可以通过设置,使大于指定大小的对象,直接进入老年代
ps:分为s0和s1区主要是用于GC算法,GC在进行的时候,会轮流到s0和s1区进行回收,当回收s0区时,没用的对象会进行直接删除,有用的对象会先拷贝一份到s1再删除。下次GC将在s1进行,过程跟上述的一样。s0区和s1区是不会同时使用的
ps2:java的基础类型的成员变量/成员变量引用,是作为一个实例数据的一部分,存在于堆中的,不是存在于栈中的
四.java栈
java栈是一块线程的私有内存空间,一个栈一般由3部分组成:局部变量表、操作数栈和帧数据区
1.局部变量表:用于报错函数的参数及局部变量
2.操作数栈:主要保存计算过程中的中间结果,同时作为计算过程中变量临时的存储空间
3.帧数据区:除了局部变量表和操作数栈以外,栈还需要一些数据来支持常量池的解析,这里帧数据区保存着访问常量池的指针,方便程序访问常量池。另外,当函数返回或者出现异常时,jvm必须要有一个异常处理表,方便发送异常时找到异常代码,因此异常处理表也是帧数据区的一部分(我们经常写的e.printStackTrace())
五.java方法区
方法区和堆一样,是所有线程共享的内存区域,保存着类的信息,比如类的字段、方法、常量池、静态变量等。方法区的大小决定了系统可以保存多少个类,如果系统定义太多的类,会导致方法区溢出,虚拟机会抛出内存溢出错误。方法区可以理解为永久区(Perm)。
六.Client和Server jvm工作模式
Client模式启动快,如果不考虑长时间使用仅仅是测试,可以使用
Server模式启动较慢,原因是会对其进行复杂的系统性能信息收集和使用更复杂的算法对程序进行优化。
一般使用Server模式
七.TLAB
全程是Thread Local Allocation Buffer 即线程本地分配缓存,从名字上看是一个线程专用的内存分配区域,是为了加速对象分配而生的。每一个线程都会产生一个TLAB,该线程独享的工作区域,jvm使用这种TLAB取来避免多线程冲突的问题,提高了对象分配的效率。TLAB空间一般不会太大,当大对象无法再TLAB分配时,则会直接分配到堆上
八.对象创建流程图
一个对象创建在什么位置,jvm会有一个比较细节的流程,根据数据的大小、参数的设置,决定如何分配以及其位置