JVM内存分布、类加载机制以及双亲委派模型

一、JVM的内存布局
JVM的内存布局分为五大部分,但是不同的jdk版本下的分布是有差距的。
jdk1.7:本地方法栈、程序计数器、虚拟机栈、堆区、永久代
jdk1.8:本地方法栈、程序计数器、虚拟机栈、堆区、元数据区

堆区
        所有的对象存放的区域,其内部分为新生代和老年代,新生代存放的是新来的对象,而我们会不断的进行垃圾回收,在进行多次回收之后还是没有被回收的对象就会放在老年代。老年代和新生代的区别是在垃圾回收的频率不一样。【线程共享】

java虚拟机栈
        存放的是方法的内存模型,每一个方法在被执行的时候都会创建一个栈,来存放局部变量,操作数,方法出口等信息。【线程私有】

本地方法栈
        本地方法栈和java虚拟机栈的意思是一样的,只是虚拟机栈给JVM使用,二本地方法栈给本地方法使用。【线程私有】

程序计数器
        表示线程执行的位置,因为线程可能存在休眠,需要重新执行的话,我们就需要记住上一次运行的位置。【线程私有】

元数据区
        存放的是常量池、类信息、方法元信息(特别的是在jdk1.8的时候,将字符串常量池转移在了堆区。)【线程共享】

线程私有和线程共享
        因为我们的JVM采用的是线程轮流获得时间片的方式来执行的,每次处理器只能执行一个线程,那么多个线程之间有的信息例如程序计数器记录的当前线程执行的位置,那这个肯定是线程私有的,我知道自己执行到哪里就好,我需要知道别人的,也不需要让别人知道我执行到哪里,所以就是线程私有的,而元数据区中的信息,例如常量池中的信息那就是大家都可以拿来用的,那他就是线程共享的。

二、类加载器
类加载的流程:加载 -> 验证 -> 准备 -> 解析 -> 初始化【其中验证 -> 准备 -> 解析也统称为连接】
加载(Loading)
        通过包名+类名获得该类的二进制字节流;然后将字节流转换放到方法区里面,比如说字符串放在常量池等;最后在内存中生成class文件,作为方法区的访问入口。
验证(Verification)
        保证class文件中的信息是符合虚拟机规范的,就像是安检一样,保证不会出现一些危害虚拟机的代码
准备(Preparation)
        给类中定义的变量分配空间,同时赋初值,初始值就是该数据类型默认的初始值
解析(Resolution)
        将常量池中的符号引用替换为直接引用。也就是给常量池中的变量进行一个初始化
初始化(Initialization)
        执行我们自己写的构造方法的过程

三、双亲委派模型
概念
        如果一个类加载器收到了一个加载类的请求,他首先会把请求发给自己的父类,每一层收到请求都会提交给父类,然后直到最顶层的类加载器收到这个请求,当父类反馈自己无法加载这个类的时候,子加载器开始加载。

双亲委派模型的优点
         他可以避免重复加载,就像A和B的父类都是C,那么加载A的时候就会把C也加载了,那么要加载B的时候就不会重复加载C类了。
        同时双亲委派模型也保证了一定的安全性,因为不向上发请求的话,每一个类加载器都会加载自己。假设我们自己也写了一个Object类,当程序运行起来了之后,就会出现多个不同的Object类,其中还有用户自定义的Object类,这样的话安全性就无法得到保证。如果我们用了双亲委派模型,然后自己编写了一个Object类之后,在最上层,系统会加载本身的Object类,这样就不会再加载用户写的那个类了,也就避免了不安全因素。

打破双亲委派模型的场景
        java中的SPI机制,其中的JDBC就打破了双亲委派模型。因为JDBC中的Driver接口定义是在jdk中的,他的实现是各个数据库厂商来编写,然后我们知道DriverManager的原码类是放在系统的rt.jar包中的,rt.jar包是由顶层的父类进行加载的,但是在具体的getConnection它的源码是子类加载器进行加载的,这样就破坏了双亲委派模型。双亲委派模型强调的是所有的类都由父类进行加载,但是我们的JDBC其中出现了由子类加载的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值