jvm内存区域

前言:jvm是java的底层,是全部java框架的底层,凡事需深刻现象看本质,知晓其原理才能更好的作上层开发。java

1、jvm的体系结构python

类装载器classloader:用来装载.class文件算法

执行引擎:执行字节码,或者执行本地方法c#

运行时数据区(这个就是本章讨论的重点):方法区、虚拟机栈、本地方法栈、堆、程序计数器  数组

2、运行时数据区缓存

一、程序计数器:能够当作当前线程所执行的字节码的行号指示器( 线程私有)多线程

二、 java虚拟机栈:存放基本数据类型、对象引用类型(线程私有)并发

三、本地方法栈:存放本地(native)方法相关信息框架

四、方法区:存放已被虚拟机加载的类型信息、常量、静态变量、及时编译器编译后额代码缓存等数据jvm

五、堆:对象实例及数组

3、对象的内存布局

对象在堆内存的存储布局能够分为三个部分:对象头、实例数据、填充数据(保证对象大小都是8字节的整数倍)

Hotspot虚拟机对象的对象头中包括两类信息:第一类是用于存储对象自身的运行时的数据,如hashcode、gc分代年龄、锁状态标志、线程持有的锁、偏向线程id、偏向时间戳,这些被称为Mark Word,另外一类是类型指针(经过其判断是哪一个类的实例)

4、垃圾收集(GC)

显然,不能全部对象一直在内存中存在,这样不停有新对象,内存就会爆掉,全部须要进行GC,而在进行GC的时候,咱们首先就须要判断哪些对象存活,哪些对象已死,下面就介绍常见的2种算法判断对象已死

一、引用计数算法(python)

在对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加一;当引用失效时,计数器就减一;任什么时候刻计数器为零的对象就是不可能再被使用的(这个算法看似很好,实则否则,当出现对象循环引用时就很难解决)

二、可达性分析(java、c#)

经过一系列称为"GC Roots"的根对象做为起始节点,根据其引用关系向下搜索,搜索过程所走过的路径被称为“引用链”,当一个对象到GC Roots之间没有任何引用链,可断定为可回收对象,不过这个时候不会直接回收掉,需进行第一次标记,随后再经过一次筛选,筛选的条件就是此对象是否有必要执行finalize(),加入对象没有覆盖finalize(),或者已经执行过一次,这认为此对象能够被回收了。

常见的GC Roots:当前或者的线程所引用的对象、方法区的静态变量、常量

三、引用的分类

引用分为如下四类:强引用、软引用、弱引用、虚引用

其中强引用就是咱们普通的new对象,只要强引用关系还存在,就不会被回收

软引用,被软引用的对象在系统进行下下次GC则回收

弱引用,被弱引用的对象在系统进行下次GC则回收

虚引用,彻底无影响对象生存时间,GC时会收到系统通知,就是一个对象存活的监控

5、垃圾收集算法

一、标记-清除算法

首先标记出须要回收的对象,在标记完成后,同一回收(显然会效率低、内存碎片化)

二、标记-复制算法

将可用内存划分为等大小2块,当一块快用完了,将其或者的对象按顺序移到另外一块上(显然浪费空间)

三、标记-整理算法

首先标记全部可回收对象,而后将其存活的对象都放一块儿,其余位置清掉

四、分代收集算法

分代是基于把堆分红如下3个部分的

新生代:通常状况下,全部新生成的对象首先放在新生代,新生代又分为Eden区域和两个Survivor(survivor0、suirvivor1)区,大部分对象在Eden区生成

老年代:存放的都是些生命周期较长的对象,在新生代中经历了屡次垃圾回收仍然存活的对象就放入老年代

元空间:存放静态文件,如java类、方法

新生代采用标记复制算法,老年代采用标记整理算法

6、经典垃圾收集器

一、Serial收集器

看其名字便知道其为单线程收集器,单线程收集器比较大的一个问题就是,会Stop the world,就是停掉正常工做的全部线程。

serial收集器中,对新生代采用标记复制算法,对老年代采用标记整理算法

二、ParNew收集器

多线程Serial收集器

三、CMS收集器

分四个步骤初始标记(STW)、并发标记、从新标记、并发清除(STW)

缺点:并发处理、致使应用程序变慢 且CMS收集器是基于标记清除的,会形成内存碎片化

四、G1收集器

大体分四个步骤初始标记、并发标记、最终标记、筛选回收

除并发标记外,其余步骤均STW

筛选回收:任意选择多个Region区进行GC,将一个Region区活着的对象放入空的Region区

G1经过把堆分红多个相对独立的区域,并行的选择性回收,兼顾STW与吞吐量,基于标记-复制算法