jvm之类加载器初步了解

类加载

Demo.java=(编译)=>Demo.class(字节码文件)=(类加载器)=>内存(分配内存)

概念:类加载时jvm将.class文件加载到内存,并对数据进行校验,转换和初始化以形成可使用Java类(Class)的机制

类的生命周期:

加载 : .class==>内存中Class对象

连接:

验证 : 验证.class文件正确性
准备 : 为静态变量分配内存.赋予默认值
解析 : 符号引用==>直接引用
实例 :

​ 在类的加载过程中的解析阶段,Java虚拟机会把类的二进制数据中的符号引用 替换为 直接引用,如Worker类中一个方法:

public void gotoWork(){
     car.run(); //这段代码在Worker类中的二进制表示为符号引用        
}

​ 在Worker类的二进制数据中,包含了一个对Car类的run()方法的符号引用,它由run()方法的全名 和 相关描述符组成。在解析阶段,Java虚拟机会把这 个符号引用替换为一个指针,该指针指向Car类的run()方法在方法区的内存位置,这个指针就是直接引用。

初始化 : 给静态变量赋值

使用 : 对象实例化 垃圾回收
卸载 : 类中不再有任何引用

类加载器 :

根类加载器(Bootstrap) :

它用来加载 Java 的核心类,是用原生代码来实现的,并不继承自 java.lang.ClassLoader(负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。

扩展类加载器(Extension) :

它负责加载JRE的扩展目录,lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现,父类加载器为null。

系统加载器 :

被称为系统(也称为应用)类加载器,它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。如果没有特别指定,则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现,父类加载器为ExtClassLoader。

自定义类加载器 :

去继承ClassLoader类实现自定义类加载器。

jvm内存分配

堆:

是虚拟机管理内存最大的一块,也是被所有线程共享的一块内存区域。对象实例及数组会在堆上进行内存分配,但也不是绝对。另外堆也是垃圾收集的主要区 域,根据垃圾收集的分带收集算法,堆还可以细分为新生代和老年代。而在物理空间上堆处于不连续的内存空间中,只要是逻辑上连续即可,既可实现固态大 小,也可以实现可扩展性(可配置-Xmx 和-Xms控制)。当内存不足无法完成实例分配,同时堆也无法进行扩展时会抛出OOM。

方法栈:

Java栈的区域很小,只有1M,特点是存取速度很快,所以在stack中存放的都是快速执行的任务,基本数据类型的数据,和对象的引用(reference)。

驻留于常规RAM(随机访问存储器)区域。但可通过它的“栈指针”获取处理的直接支持。栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。创建程序时,Java编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java数据要保存在栈里——特别是对象句柄,但Java对象并不放到其中。

JVM只会直接对JavaStack(Java栈)执行两种操作:①以帧为单位的压栈或出栈;②通过-Xss来设置, 若不够会抛出StackOverflowError异常。

1.每个线程包含一个栈区,栈中只保存基本数据类型的数据和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本数据类型的变量区、执行环境上下文、操作指令区(存放操作指令)。

栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,Java栈所占内存的大小由Xss来调节,方法调用层次太多会撑爆这个区域。

本地方法栈:

与虚拟机栈发挥作用相似,虚拟栈为执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用的Native服务。sun HOST POST 把二者合二为一,同虚拟机栈一样也会抛出OOM和StackOverflowError异常。

程序计数器:

是唯一一个没有任何规定OOM情况的区域,是一块比较小的内存空间。每条线程都需要一个独立的程序计数器,来保证线程切换后能恢复到正确的执行位置,在字节码解释器工作就是通过改变这个技术器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等功能。线程正在执行一个Java方法,计数器记录的是正在执行的虚拟机字节码指令地址,而如果正在执行Native方法,则技术器为空。

方法区:

也是各个程共享的一块区域,主要存储****已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。****也被称为“永久代”,不过在不同的虚 拟机中这两者还是有本质的区别。方法区同样支持固定大小及可扩展性,还可以选择不实现垃圾收集。同时也会出现OOM的异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值