第三章 JVM内存概述

news/2024/11/28 19:27:39/

附录:精选面试题

Q:为什么虚拟机必须保证一个类的Clinit( )方法在多线程的情况下被同步加锁 ?

A: 因为虚拟机在加载完一个类之后直接把这个类放到本地内存的方法区(也叫原空间)中了,当其他程序再来调这个类的时候直接从内存中拿的,因此Clinit( )方法只会执行一次来保证类只会被加载一次,当同时有两个线程进来操作同一个类的Clinit( )方法,可能会出现数据的不一致性,当两个线程中的某个线程抢到了类锁,而且一直在Clinit()方法中执行,另一个线程会一直保持阻塞状态

Q: 类加载子系统中的加载阶段分别有哪些类加载器 ?

A: 一般会有BootStarpClassLoader引导类加载器,ExtClassLoader扩展类加载器,ApplicationClassLoder应用类加载器。

Q: 类加载器又分为几种 ?

A: 从官方给的规范来讲,分为两种类加载器,分别是引导类加载器,和自定义类加载器。引导类加载器BootStarpClassLoader是由C语言和C++进行编写的,主要加载Java的核心类库。而直接或间接继承ClassLoader的加载器都可以认为是自定义类加载器,JVM默认提供给用户使用的是继承图最底层的ApplicationClassLoader系统类加载器,ApplicationClassLoader调用getParent( )方法一直往上面调,是获取不到BootStarpClassLoader引导类加载器的

一、内存结构

当class文件以二进制流的方式加载到JVM内存的类加载子系统时,在类加载子系统(Class Loader SubSystem)中又分三步对数据进行解析,分别是加载阶段(Lading),链接阶段(Linking),初始化阶段(Initiatlizetion)。

加载阶段有:引导类加载器(BootStrapClassLoader),扩展类加载器(ExtensionClassLoder),系统类加载器(ApplicationClassLoder),和自定义加载器。

链接阶段:验证(Verify),准备(Prepare),解析(Resolve)。

最后把数据一起放入初始化阶段

二、类加载器和类加载过程

ClassLoader 只负责class文件的加载,至于是否可以运行,则有ExecutionEngin(执行引擎) 决定。

Loading加载阶段

链接阶段(Linking)

初始化阶段(Initiatlizetion)

程序加载到初始化阶段<clinit>( )方法会收集静态变量赋值的动作,在连接阶段(Linking)先为静态变量(类变量)赋0值,当程序走到初始化阶段从上到下收集赋值动作,赋值给静态变量。

当类中没有声明过静态变量或者静态代码块时,类加载子系统在进行到初始化阶段时就不会创建<clinit>( )方法。

变量声明在静态代码块的后面,可以在静态代码块进行赋值,但不能进行调用,报错信息为 “非法的前向引用”

任何一个类都会有 init( )方法(用来初始化类对象),但都有Clinit( )方法(用于收集静态变量,供该类全局使用)

Q:为什么虚拟机必须保证一个类的Clinit( )方法在多线程的情况下被同步加锁。

A: 因为虚拟机在加载完一个类之后直接把这个类放到本地内存的方法区(也叫原空间)中了,当其他程序再来调这个类的时候直接从内存中拿的,因此Clinit( )方法只会执行一次来保证类只会被加载一次,当同时有两个线程进来操作同一个类的Clinit( )方法,可能会出现数据的不一致性,当两个线程中的某个线程抢到了类锁,而且一直在Clinit()方法中执行,另一个线程会一直保持阻塞状态。

三、类加载器的分类

下面这一张图的几种类加载器是等级关系,例如文件目录上下级。但绝不能理解为是 继承关系。BootClassLoader是用C和C++编写的,而下面的几个类加载器是Java语言编写的,都间接继承了ClassLoader。

是一种像文件夹一样的包含关系。A文件夹包含B文件夹,B文件夹又包含着C文件夹,ClassLoader.getSystemClassLoader( ) 方法获取到ApplicationClassLoader。

也可以认为BootStarpClassLoader只负责加载Java程序的核心类库,自定义的加载器太low了,不配“高端”加载器出手帮忙,另外一方面,BootStarpClassLoader是使用C和C++进行编写的,自热而然的就获取不到它的对象了。

public class ClassLoaderTest {public static void main(String[] args) {//获取系统类加载器ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2//获取其上层:扩展类加载器ClassLoader extClassLoader = systemClassLoader.getParent();System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@1540e19d//获取其上层:获取不到引导类加载器ClassLoader bootstrapClassLoader = extClassLoader.getParent();System.out.println(bootstrapClassLoader);//null//对于用户自定义类来说:默认使用系统类加载器进行加载ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2//String类使用引导类加载器进行加载的。---> Java的核心类库都是使用引导类加载器进行加载的。ClassLoader classLoader1 = String.class.getClassLoader();System.out.println(classLoader1);//null}
}

引导类、扩展类、系统类加载器的使用及演示

引导类加载器

在上面我们看到,从最底层的systemClassLoader系统类加载器,调用 getParent( )方法会调用到它上层的一个扩展类加载器和应用类加载器对象,这些两个类加载器对象也都需要加载。都是通过BootStarpClassLoader引导类加载器进行加载的,所以也就把BootStarpClassLoader、ExtClassLoader、ApplicationClassLoader都认为是系统核心类库。

扩展类加载器扩展类加载器扩展类加载器扩展类加载器扩展类加载器扩展类加载器扩展类加载器扩展类加载器扩展类加载器扩展类加载器

应用程序类加载器应用程序类加载器应用程序类加载器应用程序类加载器应用程序类加载器应用程序类加载器应用程序类加载器应用程序类加载器应用程序类加载器应用程序类加载器

自定义类加载器自定义类加载器自定义类加载器自定义类加载器自定义类加载器

自定义加载器

package com.atguigu.java1;import java.io.FileNotFoundException;/*** 自定义用户类加载器* @author shkstart* @create 2019 下午 12:21*/
public class CustomClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] result = getClassFromCustomPath(name);if(result == null){throw new FileNotFoundException();}else{return defineClass(name,result,0,result.length);}} catch (FileNotFoundException e) {e.printStackTrace();}throw new ClassNotFoundException(name);}private byte[] getClassFromCustomPath(String name){//从自定义路径中加载指定类:细节略//如果指定路径的字节码文件进行了加密,则需要在此方法中进行解密操作。return null;}public static void main(String[] args) {CustomClassLoader customClassLoader = new CustomClassLoader();try {Class<?> clazz = Class.forName("One",true,customClassLoader);Object obj = clazz.newInstance();System.out.println(obj.getClass().getClassLoader());} catch (Exception e) {e.printStackTrace();}}
}
package com.atguigu.java1;/*** @author shkstart* @create 2020 上午 10:59*/
public class ClassLoaderTest2 {public static void main(String[] args) {try {//1.获取引导类加载器 获取不到 nullClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();System.out.println(classLoader);//2.获取系统类加载器  sun.misc.Launcher$AppClassLoader@18b4aac2ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();System.out.println(classLoader1);//3.获取扩展类加载器  sun.misc.Launcher$ExtClassLoader@1b6d3586ClassLoader classLoader2 = ClassLoader.getSystemClassLoader().getParent();System.out.println(classLoader2);} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

http://www.ppmy.cn/news/105075.html

相关文章

【踩坑】mirai挂机运行经常自动退出怎么办?

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 目录 背景介绍 解决思路 实现方法 最终效果 背景介绍 就是说&#xff0c;后台运行了mcl&#xff0c;但经常莫名其妙自动会退出&#xff0c;导致每次都得手动的去服务器上重新启动mcl。而对于自己运行的需要用…

Java制作520表白代码——爱一个人需要理由吗?

✨博主&#xff1a;命运之光 ✨专栏&#xff1a;Java经典程序设计 520表白日&#xff0c;每个人都期待着浪漫的表白&#xff0c;而作为一名热爱编程的程序员&#xff0c;我决定用程序员的方式来向你表达我的爱意。 在2023年5月20日这个特殊的日子里&#xff0c;我要用一段特别的…

kong网关安装及konga安装

一、kong安装 安装机器地址&#xff1a;192.168.19.50 1、自定义一个docker网络 [rootmin ~]# docker network create kong-net a9bde4e7d16e4838992000cd5612476b238f7a88f95a07c994a9f57be7f64c10查看网络是否创建成功 [rootmin ~]# docker network ls NETWORK ID NA…

【计算机网络详解】——应用层(学习笔记)

&#x1f4d6; 前言&#xff1a;应用层是计算机网络体系结构的最顶层&#xff0c;是设计和建立计算机网络的最终目的&#xff0c;也是计算机网络中发展最快的部分。在本文中&#xff0c;我们以一些经典的网络应用为例来学习有关网络应用的原理、协议和实现方面的知识。 目录 &a…

Vue实例

1. 自定义元素 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-wid…

基于FPGA:运动目标检测(包围盒仿真工程,及一些调试问题)

目录 前言一、安装器件库二、仿真工程操作1、进入文件列表2、找到bounding_box_locate.vt&#xff0c;双击打开文件3、修改路径4、路径设置5、切换回“Hierarchy”&#xff0c;即工程界面6、运行仿真7、查看波形 重点&#xff1a;调试问题三、仿真代码1、仿真顶层文件2、绘制包…

什么是Redis

概述 什么是Redis Redis(Remote Dictionary Server) 是一个使用 C 语言编写的&#xff0c;开源的&#xff08;BSD许可&#xff09;高性能非关系型&#xff08;NoSQL&#xff09;的键值对数据库。 Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串&#xff…

Linux输入输出重定向

目录 Linux输入输出重定向 Linux中的默认设备 输入输出重定向定义 输入输出重定向操作符 实用形式 标准输入、标准输出、标准错误 输出重定向案例 案例1 --- 输出重定向&#xff08;覆盖&#xff09; 案例2 --- 输出重定向&#xff08;追加&#xff09; 案例3 --- 错误…