2019-10-27

- 内存模型总览

- 类加载机制

- 堆内存(新生代,老生代),GC回收区  垃圾回收算法

- 方法区

- 程序计数器

- 栈内存

java内存模型图:

2019-10-27_第1张图片

jvm内存模型粗略得可以分为三个部分:堆内存,方法区,堆栈(线程私有)。

有些地方会把方法区归为堆内存,但实际上方法区还有另一个名字叫(非堆),也会被称为永久代(但实际上也会存在GC),不过java8已经把方法区移到了元空间,存在于本地内存。

堆内存可以分为新生代区和老生代区,而新生代区有Eden,From Survivor,To Survivor(8:1:1)。

参数配置图解:

-Xms  最小堆内存

-Xmx  最大堆内存

-XX:NewSize 最小新生代内存

-XX:MaxNewSize 最大新生代

-XX:PerSize 最先永久代内存

-XX:MaxPerSize 最大永久代呢村

-Xss:  单个线程栈内存大小

2019-10-27_第2张图片

JVM与系统之间得关系图:

2019-10-27_第3张图片

1,类加载机制

- 类加载过程:当java文件被编译后,生成的.class文件会被类加载器加载到运行时数据区,然后执行链接的步骤,包含对字节码内容进行验证,初始化分配做准备(设置默认值),当该类被实例化时,则先执行初始化。

-最终结果:java文件被编译成.class文件,类加载器把字节码文件加载到运行时数据区,并在堆中创建类的相关java.lang.Class对象,用来封装类在方法区的数据结构。jvm根据根据在这些数据运行程序。

- 类加载器:java的类加载器概括来说包含两种,启动加载器和其他加载器;启动加载器是虚拟机的一部分由c语言实现,他可以负责加载其他加载器的class。   

- 双亲委派模型:类加载器存在继承关系时,当前类加载器会讲需要加载的目标传递给父类加载器,当父类不能加载时,则就近加载;确保内存中只存在一份字节码数据!

2,堆内存

作用:存储程序中所有对象实例数据和类的Class对象(如上所说)的区域,为所有线程之间共享。

结构:堆内存会被分有新生代和老生代,老生代又可以分为伊甸区,FromSpace, ToSpace,其中不同区域对应的垃圾回收算法也会不同。

jvm中的垃圾回收算法:

标记清除-对于可回收的对象先标记再清除,效率高;适用于新生代对象更新频繁,从而会留下更多大块的内存区域。

标记整理-先标记,清除再整理,相比标记清楚,多了整理的步骤,所以适用于老生代不会频繁调用回收机制。

复制算法:将内存分为两块区域,轮流替换使用。不适合对象存活周期长的区域,频繁的复制会大大降低回收效率

分代回收算法:根据内存特征选择不同的回收算法

3,方法区

用途:保存的是被虚拟机加载的类信息,常量,静态变量等编译后的代码信息。也是线程共享区域。

方法区的特点是对象的回收率低,存活周期长。因此,不适合使用复制算法回收

jdk1.8使用元空间代替方法区,元空间也不存在在虚拟内存中,而是使用的实际物理内存。

4,程序计数器

用途:记录每个线程执行指令位置,为线程私有。

程序计数器在内存中只会占用一小块内存,用于线程专门记录指令执行位置,当CPU在线程之间进行切换的时候,便于线程恢复到相应的位置。

5,栈内存

用途:栈内存是线程私有,每开启一个新线程都会创建一块该线程所私有的内存。

a栈内存模拟了线程开始执行方法到结束的过程模型,

b线程没执行一个方法都会创建一个栈帧,栈帧保存了方法中的局部变量,方法出口等信息。

栈帧所分配的内存在编译期间就确定了。

异常:

1,当线程请求的站深度超过了jvm所规定的深度,则会抛出栈溢出异常。意思是线程调用方法深度超过了虚拟机规定的深度。

2,当线程无法申请到扩充栈的内存失败时,会抛出内存溢出

你可能感兴趣的:(2019-10-27)