对于HotSpot内存板块划分及工作方式的整理
1 堆内存
young空间被分为两个部分、三个板块, 一个Eden区和两个survivor区
eden区:使用new或者newInstance创建的新对象默认放入该区域。 特殊情况 1)如果此时对象太大eden区域放不下 会直接进入old区 2)设定了对象阈值-XX:PertenureSizeThreshold会直接进入old区
old区:常量,反反复复younggc都没死掉的对象或者说s0或s1满了,放不下而进入的old区对象
几个区域如何配合工作?
不断创建对象的过程中,会往eden区放,放满后就会做youngGC(MinorGC)操作,这时候会将eden中活的对象向s0或者s1里存放。若eden区域再次发生youngGC的时候将活的对象放入空的survivor空间,并将原先存入s0或者s1的活对象(根可达或者引用 例:本地变量引用,操作数栈引用,pc寄存器,本地方法栈引用,静态引用)一并存入另一个survivor,此时清理动作会清理eden+s0或s1
前面说到youngGC发生时会有个临时空间s0或者s1 并且youngGC大部分对象是会被清理的只有少数对象会存活下来进入old区域,而当发生fullGC时,会对old区进行碎片清理,需要遍历old区 若中间有发生对象清理,这时候会产生内存碎片,所以如果活对象越多,整理一次碎片消耗的代价就越大,fullGC是我们不想看到的GC
so与s1靠什么参数来设置比重?
-XX:SurvivorRatio=2 和 -XX:InitalSurvivorRatio=2
第一个参数:Eden/Survivor的比重,Eden区是一个survivor区的2倍
第二个参数:Young/s0或s1 的比重 1/2
2 非堆内存
3 jvm内存结构
.class 类文件通过classLoader加载至jvm内存, class也是一种的对象堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
方法区:
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
程序计数器:
它保存的是程序当前执行的指令的地址(也可以说保存下一条指令的锁在的存储单元的地址),当CPU需要执行指令时,需要从程序计数器中得到当前需要执行的指令锁在的存储单元的地址,然后根据得到的地址获取到指令,在得到指令之后,程序计数器便自动加1或者根据转移指令得到下一条指令的地址,如此循环,直至执行完所有的指令。
本地方法栈:
为执行本地方法(Native Mehotd)服务的。在JVM规范中,并没有对本地方法的具体实现方法以及数据结构做强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接把本地房发栈和java栈合二为一。
执行引擎:
一条一条的读取,解释并执行字节码指令。因为它一条一条地解释和执行命令,所以他可以很快的解释字节码,但是执行起来会比较慢。这是解释执行的语言一个缺点。字节码这种“语言” 基本说是解释执行的。 执行引擎引入了即时(Just-In-Time)编译器来弥补解释器的缺点。执行引擎首先按照解释执行的方法来执行,然后在适合的时候,即时编译把争端字节码编译成本地代码。然后,执行引擎就没有必要再去执行方法了,他直接可以通过本地代码去执行它。执行本地代码比一条一条解释执行的速度快很多,编译后的代码可执行的很快,因为本地嗲吗是保存在缓存里的。
本地接口:
是负责调用本地接口的。他的作用是调用不同语言的接口给JAVA用,他会在Native
Method Stack中记录对应的本地方法,然后调用该方法时就通过Execution Engine加载对应的本地lib。原本多于用一些专业领域,如JAVA驱动,地图制作引擎等,现在关于这种本地方法接口的调用已经被类似于Socket通信,WebService等方式取代。
本地类库:顾名思义,JVM根据不同的操作系统,调用不同的系统函数库。