概述

类加载:将类从class文件加载到内存中,并且对字节码进行校验、准备、解析和初始化,最终转换为可以被JVM直接使用的Java类型。

类加载的过程

加载——验证——准备——解析——初始化——使用——卸载

准备

虚拟机在准备阶段为类变量(static修饰)分配内存,并设置类变量的初始值。这些内存是在哪里分配的?堆里?答案是方法区。

而实例变量则是在初始化阶段随对象一起分配在堆内存。而且这里要注意private static int a = 1;在准备阶段,a为0而不为1,在初始化阶段,a才被赋为1

解析

解析阶段是将 常量池中的符号引用替换为直接引用

初始化

遇到下列4种情况,必须对类进行初始化

(1)有new、getstatic、putstatic、invokestatic

(2)反射调用时,如果类没有初始化,就必须首先对类初始化

(3)初始化一个类时,如果父类没有被初始化,就首先对父类进行初始化。

(4)虚拟机启动时需要指定一个主类(main方法所在的类),虚拟机必须首先对其初始化

监控类的加载

-XX:+TraceClassLoading

被动引用不会触发类的初始化

(1)子类引用父类的静态字段,不会引起子类的初始化


class Father{ public static int a = 1; static{
System.out.println("father");
} } class Son extends Father{ public static int b = 2; static {
System.out.println("son");
} } public class ClassLoaderDemo { public static void main(String[] args) {
System.out.println(Son.a);
} }

原因是,该静态变量虽然是子类引用,但底层还是属于父类的。

(2)通过数组定义引用类,不会触发类的初始化


public class ClassLoaderDemo { public static void main(String[] args) {
Father[] fathers = new Father[10];
} }

只加载,并未初始化。

(3)常量在编译的阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量类的初始化


class Father{ public static final int a = 1; static{
System.out.println("father");
} } public class ClassLoaderDemo { public static void main(String[] args) {
System.out.println(Father.a);
} }

对象占用空间计算

dir

类加载器

运行期间动态加载

JVM对class文件并不是全部加载,而是按需加载,需要的时候才会加载进来。

启动时加参数-verbose:class,打印类加载顺序。


class A{
static {
System.out.println("A");
}
}
public class ClassLoaderDemo2 { public static void main(String[] args) {
System.out.println(String.valueOf("test"));
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
A a = new A();
} }

运行结果,会发现只有当执行到new A()是,A类才会被加载进来。

双亲委派机制

先委托父类加载器寻找目标类,在找不到的情况下,在自己的路径中查找目标类。

是否可以创建一个全限定名相同的String类

不可以。当AppClassLoader加载该String时,判断java.lang.String已经加载,便不会再次加载。所以执行的依旧是jdk中的String,但是系统的java.lang.String中没有main()方法,所以会报错。这是一种安全机制。


package java.lang; public class String { public static void main(String[] args) {
System.out.println("test");
} }

异常信息如下

那么String是由哪个加载器加载的?

打印为null,说明是启动类加载器加载的,由于该加载器是C++实现,所以返回null。


public class ClassLoaderDemo2 { @Test
public void testStringClassLoader(){
// 打印为null,说明是启动类加载器加载的,由于该加载器是C++实现,所以返回null
System.out.println(String.class.getClass().getClassLoader());
} }

启动类加载器(Bootstrap CLassLoader)

无法被Java程序直接引用。它属于JVM内部使用的类加载器,既没有上级类加载器,也没有下级类加载器,因此不遵守ClassLoader的上级委托机制,只能算是JVM的一个类加载工具。

扩展类加载器(Extension CLassLoader)

应用程序类加载器(Application CLassLoader)

1、为什么Java可以跨平台

因为有java虚拟机,跨平台是因为字节码即class文件具有平台无关性,java代码会经过java虚拟机转换为字节码

2、class文件的结构

class文件主要是以8位字节码为基本单位的二进制文件,主要的存储方式是以类似于c语言的结构体来存储,其中的两种基本类型为无符号数和表,其中表中又会有其他的表和一些无符号数。就好比结构体中有一些变量,还有一些其他的结构体

class文件的不同位置是固定的,第一个字节码是魔数,紧接着是次版本、主版本、常量池变量数,常量池变量表.......


<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
</dependency>

//计算指定对象及其引用树上的所有对象的综合大小,单位字节

long RamUsageEstimator.sizeOf(Object obj)

//计算指定对象本身在堆空间的大小,单位字节

long RamUsageEstimator.shallowSizeOf(Object obj)

//计算指定对象及其引用树上的所有对象的综合大小,返回可读的结果,如:2KB

String RamUsageEstimator.humanSizeOf(Object obj)


public class A { static{
System.out.println("A");
} } public class B extends A{ static{
System.out.println("B");
} }

Java虚拟机——类的结构与加载的更多相关文章

  1. windows/tomcat 修改java虚拟机JVM以utf-8字符集加载class文件的两种方式

      1.情景展示 做了这么长时间的java开发,但是,你知道JVM是以怎样的编码加载.解析class文件的吗? 我们知道,通常情况下,我们会将java文件的字符集修改成utf-8,这样,理所当然地就认 ...

  2. [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义

    前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine  ,既然是虚拟机, ...

  3. java类到底是如何加载并初始化的?

    Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就 是解决上面3个问题的. 若有不正之处, ...

  4. java类的编译、加载和执行

    一.java类的编译流程 这里主要讲的是从java文件到class文件 下图是java类编译的详细步骤: 1.词法分析:将java源代码的字符流转变为标记(Token)的集合,Token是编译过程中的 ...

  5. (转)java类到底是如何加载并初始化的?

    Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就 是解决上面3个问题的. 若有不正之处, ...

  6. java中class.forName和classLoader加载类的区分

     java中class.forName和classLoader都可用来对类进行加载.前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块.而classLoade ...

  7. java类在何时被加载

    我们接着上一章的代码继续来了解一下java类是在什么时候加载的.在开始验证之前,我们现在IDEA做如下配置. -XX:+TraceClassLoading 监控类的加载 我们新建了一个TestCont ...

  8. 你知道 Java 类是如何被加载的吗?

    前言 最近给一个非 Java 方向的朋友讲了下双亲委派模型,朋友让我写篇文章深度研究下JVM 的 ClassLoader,我确实也好久没写 JVM 相关的文章了,有点手痒痒,涂了皮炎平也抑制不住的那种 ...

  9. Java 类中各成分加载顺序 和 内存中的存放位置

    参加一个笔试,有一个关于类的静态代码块.构造代码块.构造函数的执行顺序的问题.不太清楚,网上百度了一下.在这里记录一下. 一.什么时候会加载类?使用到类中的内容时加载:有三种情况1.创建对象:new ...

随机推荐

  1. win7里linux虚拟机安装vmware tools(ubuntu12.04)

    安装Vmware Tools工具 1.安装linux虚拟机(略) 2.虚拟机去启动,选择虚拟机à设置,“硬件”中选择CD/DVD(IDE),右侧选择“使用ISO镜像文件(M)”  -- 文件选择vmw ...

  2. B - Big Event in HDU

    Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don't k ...

  3. Python Memo 赋值与ID (Assignment & id())

    利用Python内置函数id()找出内部地址,探讨赋值与内建地址. id()的官方解释:this is the address of the object in memory 那么 a =1 是什么意 ...

  4. arp脚本

    1.什么是arp?arp可以解决什么问题? ARP:是地址解析协议 arp解决我们知道一个机器(主机或者路由器)的IP地址,需要找出其相应的硬件地址 2.编写ARP脚本,抓取对应主机的mac地址 1 ...

  5. Android-finished with non-zero exit value 2

    网上都是说,由于导入的依赖出现重复造成的,或者说 由于buildtools版本太高造成的,而我遇到的这个问题,这种两种方式无法去解决,所以才有了一下这种解决方式: 第一步,打开项目最外层的 build ...

  6. 记一次生产环境thrift服务的配置问题

    问题现象 有客户反馈我们的产品有时反应很慢,处理会出现超时. 问题分析过程 1.第一反应可能是用户增加,并发量太大了,询问了运营,最近用户注册数据并没有猛增. 2.分析access日志,发现有隔一段时 ...

  7. 移动APP外挂攻防实战

    前言 近日,某某龙在2018年的一次会议上发表了一个演讲,4000多人聚集在现场玩“跳一跳”游戏.随着他们指尖的翻飞跳跃,大屏幕上的现场排名也在不断刷新……而在全场的惊叹声中,最高分出现了,967分! ...

  8. Jenkins关闭和重启实现方式.

    1.关闭Jenkins 只需要在访问jenkins服务器的网址url地址后加上exit.例如我jenkins的地址http://localhost:8080/,那么我只需要在浏览器地址栏上敲下http ...

  9. metools,个人工具站点分享

    需要[加密/解密][编码/解码][生成二维码]的时候不用再进百度点广告~ 也不需要去收藏夹找网址~ 我的目的大概就是如此. 项目地址:https://github.com/yimogit/metool ...

  10. IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

    1.前言 在IM这种讲究高并发.高消息吞吐的互联网场景下,MQ消息中间件是个很重要的基础设施,它在IM系统的服务端架构中担当消息中转.消息削峰.消息交换异步化等等角色,当然MQ消息中间件的作用远不止于 ...