目录

一、JVM架构图

1.1、宏观jvm

1.2、JVM架构图

二、类装载器

2.1、类装载器

2.1.1、分类

加载器

存在位置

特点

BOOT(根加载器)

Environment/jdk8/jre/lib/rt.jar

用原生C++代码来实现的,并不继承自java.lang.ClassLoader(查不到)

EXC(扩展类加载器)

Environment/jdk8/jre/lib/ext/*.jar

Java 虚拟机提供一个扩展库目录用来加载 Java 的扩展库,该类加载器在此目录里面查找并加载 Java 类。

APP(应用程序加载器 / 系统类加载器)

CLASSPATH

它根据 Java 应用的类路径来加载自己写的 Java 类

自定义类加载器

除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

2.1.2、作用

作用:加载class文件到虚拟机

将class文件码加载到内存中,

将静态数据转化成方法区的运行时数据结构

在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。

代码查看

// 创建Car实例

Car car1 = new Car();

Car car2 = new Car();

// 可以看出同一个类,创建出的实例不同

System.out.println(car1.hashCode());

System.out.println(car2.hashCode());

// 实例转类,类时相同的

Class extend Car> clazz1 = car1.getClass()

Class extend Car> clazz2 = car2.getClass()

System.out.println(clazz1.hashCode());

System.out.println(clazz2.hashCode());

// 获取类加载器

System.out.println(ClassLoader.getSystemClassLoader()); // AppClassLoader

System.out.println(clazz1.getClassLoader()); // AppClassLoader

System.out.println(clazz1.getClassLoader().getParent()); // ExtClassLoader

System.out.println(clazz1.getClassLoader().getParent().getParent()); // BootClassLoader(null:获取不到)

流程梳理

2.2、双亲委派机制

双亲委派机制

1、类加载器收到类加载的请求

2、将请求一直向上委托直到根加载器(启动类加载器)

3、从根加载器开始向下检查,能加载就结束,不能加载就抛异常,通知子加载器进行加载,直到可以加载当前这个类。

三、Native

3.1、引言

一般在类中是不能定义接口的,比如

private void start0(); // 定义在类中会报错

但是,查看线程的代码可以发现

new Thread().start();

private native void start0(); // 在Thread类中,存在这样一个奇怪的接口,由native修饰

这是由于,java本身是不能直接控制操作系统的线程的,这超过了java的作用范围,因此,底层使用C++/其他语言进行功能的实现,提供接口,并以native修饰,用于java调用。从而扩展java的能力

3.2、Native功能

调用其他语言,扩展java的能力

四、Program Counter Register

4.1、概述

4.1.1、PC寄存器由来

冯.诺依曼计算机体系结构的主要内容之一:程序预存储,计算机自动执行。

处理器要执行的程序都是以二进制代码块的方式存储在计算机的存储器中,

处理器将这些代码逐条的取到处理器中,再编译执行,以完成整个程序的执行。

为了保证程序能够连续的执行下去,CPU必须具有某些手段来确定下一条取址指令的地址,

程序计数器正是起到这种作用,因此又被称为指令计数器。

4.1.2、JVM指令与PC寄存器、CPU的关系

写个测试类Demo.java

void test(){

int ids[]=new int[5];

Object objs[]=new Object[5];

Object obj=new Object();

Hello hello=new Hello();

int len=objs.length;

}

使用命令javap -v Demo.class 进行反编译, 可以得到代码的JVM指令(加序列号的指令)

void test();

Code:

0:iconst_5

1:newarray int

3:astore_1

4:iconst_5

5:anewarray#2; //class java/lang/Object

8:astore_2

9:new#2; //class java/lang/Object

12:dup

13:invokespecial#1; //Method java/lang/Object."":()V

16:astore_3

17:new#3; //class Hello

20:dup

21:invokespecial#4; //Method "":()V

24:astore4

26:aload_2

27:arraylength

28:istore5

30:return

JVM指令与PC寄存器、CPU的关系

4.2、功能

功能

保存当前执行指令的地址,一旦指令执行,程序计数器将更新到下一条指令

保证程序可以正常往下执行

特性

每一个线程都有一个PC寄存器,是线程私有的,生命周期与线程的生命周期保持一致

它是一块很小的内存空间,几乎可以忽略不计。也是运行速度最快的存储区域

任何时间,一个线程只会有1个方法在执行,而PC寄存器便是存的改方法的JVM指令的序号,而如果执行的是Native方法,则存储undefined,因为程序计数器不负责本地方法栈。

它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成

它是唯一一个在java虚拟机规范中没有规定任何OOM(Out Of Memery)情况的区域,而且没有垃圾回收

常见面试问题

1、为什么要使用PC寄存器?

在多线程中,CPU需要不停的切换各个线程,这时候切换回来以后,就得知道接着从哪开始继续执行,

而PC寄存器可以存储指令的序号,方便线程切换回来还能继续执行

2、PC寄存器为什么会设定为线程私有?

因为线程是来回切换的,一个线程一个PC寄存器,更方便各个线程间独立计算,从而避免相互干扰的情况。

五、元空间

发展历程:永久代、方法区 ----> 元空间

java8之前有永久代,永久代与方法区在一起,并与堆是同一块内存(逻辑上是分开的),Java8,HotSpots取消了永久代,元空间(Metaspace)登上舞台,方法区存在于元空间(Metaspace)。同时,元空间不再与堆连续,而且是存在于本地内存(Native memory)。当Java Heap空间不足时会触发GC,但Native memory空间不够却不会触发GC。元空间存在于本地内存,意味着只要本地内存足够,它不会出现像永久代中“java.lang.OutOfMemoryError: PermGen space”这种错误。默认情况下元空间是可以无限使用本地内存的,但为了不让它如此膨胀,JVM同样提供了参数来限制它使用的使用。

jdk1.6及之前:存在永久代,常量池在方法区,与堆是同一块内存(逻辑上是分开的)

jdk1.7: 存在永久代,慢慢去永久代,常量池放在堆中

jdk1.8及之后:无永久代,常量池放在元空间,元空间的内存不再与堆公用,元空间存在于本地内存。

为什么使用元空间替换永久代?

避免了OOM异常。因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。

当使用元空间时,可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制。

特点

1、被所有线程共享,属于共享区间

2、静态变量 + 类信息(构造方法/接口定义) + 运行时常量池存 在元空间中 。实例变量 、字符串常量池存在 堆内存。

运行时常量池和静态常量池存放在元空间中,而字符串常量池依然存放在堆中。

六、栈

6.1、栈帧

什么是栈帧?

每个方法调用时占用的内存

组成

局部变量表、操作数栈、动态链接、方法返回地址

局部变量表

存放局部变量的列表

操作数栈

一个先进后出的栈

动态链接

指向运行时常量池的引用

方法返回地址

包括正常/异常返回,不同的返回类型返回不同的指令

6.2、栈

什么是栈?

在线程执行的过程中,需要内存空间,而栈即是线程的内存空间,每个线程都会有一个栈,是线程私有的。

是一种先进后出的数据结构(栈先进后出(FIFO: First input First output) ,这就是为什么main先执行最后结束 main方法最先压栈)

与栈帧的关系

程序的执行是调用方法实现的,每个方法定义一个栈帧,因此在虚拟机栈中会有一个或多个栈帧

每个线程有一个栈,每个栈只有一个活动栈帧(对应着正在执行的那个方法)

功能

主管程序运行、生命周期、线程同步,程序结束,栈内存释放,所以对于栈来说不存在垃圾回收问题

存放

8种基本数据类型、对象的引用地址、实例的方法

栈满了

StackOverflowError

七、堆

7.1、概述

JVM中,用于存放对象实例的内存空间,线程共享。

7.2、堆的组成

一个JVM只有一个堆,堆内存的大小可以调节

八、GC(垃圾回收机制)

8.1、垃圾回收概述

概述

当一个启动类加载了过多的jar包、Tomcat部署了太多的应用、大量动态生成的反射类等情况会造成JVM堆中内存不足,则会报OOM错误,而垃圾回收机制就是用来清理内存,控制OOM的发生

作用区域

8.2、GC算法

8.2.1、常见算法

引用计数法

算法描述

每个对象都配置一个计数器,清除掉计数为0(没被使用)的对象

缺点

要给每个对象创建一个计数器,计数器本身也消耗内存

复制算法

算法描述

1、对象进入S0(From),进入后S1(To)为空

2、将S0数据复制到S1(S1变为From),删除S0数据(S0变为To)

3、循环往复

优缺点

优点:没有内存的碎片、没有计数器效率高

缺点:浪费一般的内存(To区一直是空的)

使用场景

由于S0 S1要相互复制,避免进入的对象较多,复制消耗大,因此使用场景是要对象存活率低,而新生代对象存活率较低,比较适合复制算法

标记清除算法

算法描述

1、扫描所有对象,并对对象进行标记(标记非垃圾对象)

2、扫描,对没有标记的对象进行清除

优缺点

优点:不需要额外的空间,相对于复制算法节省空间

缺点:需要扫描两次浪费时间、会产生内存碎片

标记整理算法

算法描述

1、扫描所有对象,并对对象进行标记(标记非垃圾对象)

2、扫描,对没有标记的对象进行清除

3、扫描,压缩,防止碎片内存产生

优缺点

优点:不需要额外的空间,相对于复制算法节省空间、解决了产生内存碎片的问题

缺点:需要扫描三次两次浪费时间

分代收集算法

算法描述

分代收集算法是针对不同代,采用不同的算法,年轻代使用复制算法,年老代使用标记清除+标记压缩混合

8.2.2、常见算法对比

算法对比

内存效率:复制算法 > 标记清除算法 > 标记整理算法(时间复杂度)

内存整齐度:复制算法 = 标记整理算法 > 标记清除算法

内存利用率:标记整理算法 = 标记清除算法 > 复制算法

每种算法都有优缺点,没有最好的算法,只有最适合的算法

可以根据采用分代收集算法,对不同代采用不同的算法

算法选择:分代收集算法

年轻代

复制算法(因为年轻代存活率低)

年老代

标记清除+标记压缩混合(因为存活率较高)

8.3、Java GC流程

Java GC才用了分代收集算法,对新生代和老年代分别使用了不同的GC算法

java虚拟机架构图,图解快速入门Java虚拟机JVM相关推荐

  1. java 判断类型_如何快速入门Java编程学习(干货)

    一.初识Java 1.生活中的程序: 从起床到教室上课的过程 穿衣打扮>起床>洗漱>出宿舍>>吃早餐>到教室 按照特定的顺序去完成某一件事的过程我们叫做生活中的程序 ...

  2. java速学_5分钟快速入门Java,不看真的可惜了

    你好,世界! 源代码组织方式 Java程序由package+class组成,package对应目录的相对路径,class对应文件,如 关于class有如下几点规则: 文件的名字必须和class的名字一 ...

  3. java学习_Java编程学习难不难 怎样才能快速入门Java

    Java编程学习难不难?怎样才能快速入门Java?对于想要加入IT行业的人来说,Java是一个不错的选择,不仅人才需求大,就业薪资也非常不错.许多人都非常看好Java发展前景,接下来千锋小编就给大家介 ...

  4. Java基础-SSM之mybatis快速入门篇

    Java基础-SSM之mybatis快速入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 其实你可能会问什么是SSM,简单的说就是spring mvc + Spring + m ...

  5. Java好学吗?Java能做什么?如何快速入门Java?

    Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,Java具有简单性.面向对象.分布式.健壮性.安全性.平台独立与可移植性.多线程.动态性等 ...

  6. 好程序员Java培训分享如何快速入门Java编程

    好程序员Java培训分享如何快速入门Java编程,作为老牌编程语言,Java拥有广阔的市场应用,企业对Java人才的需求一直居高不下.有很多非专业.零基础的人想要学习Java却不知道怎么快速入门,接下 ...

  7. 视频教程-Spring boot快速入门-Java

    Spring boot快速入门 十年项目开发经验,主要从事java相关的开发,熟悉各种mvc开发框架. 王振伟 ¥12.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术好课免费看 ...

  8. Java好学吗?零基础入门Java,三个就业方向实现月入过万!

    Java好学吗?零基础入门Java容易吗?据统计,这是很多人学习前最常问也是最关心的问题之一. 不可否认,大家在开始接受新事物的时候都会陷入困境,但学习是循序渐进的,零基础入门Java到底难不难,只有 ...

  9. java azure blob 查询_快速入门:适用于 Java 的 Azure Blob 存储客户端库 v8 | Microsoft Docs...

    您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn. 快速入门:使用 Jav ...

最新文章

  1. MPU6050姿态融合(转载)
  2. lombok pom.xml依赖
  3. 爬虫笔记7正则表达式与re库
  4. 【ThinkPHP】实例化模型的方法
  5. Unit23 Can I help you?
  6. Linux静态库与动态库
  7. 睡觉前后爆笑的情侣小两口~媳妇不要闹了~
  8. Linux学习之基础命令
  9. 二十、Java基础--------IO流之其他对象
  10. 谷歌波浪推行受阻 “医疗云”生不逢时
  11. JavaWeb的环境配置
  12. html中字体 楷体_HTML字体集锦-
  13. python调用 ole:win32com用法详解
  14. Homography 单应性变换详解
  15. opencv学习笔记(三)分离颜色通道多通道颜色混合
  16. php halt,thinkphp-调试halt
  17. 最近3年股息率最高排名
  18. 【编译原理·总复习】第二章||文法语言||语法树||最左最右推导归约||句柄直接短语||例题+知识点
  19. world分节及分节首页分节页码总页码设置方法
  20. 网上买电信电话卡又被欺骗百元

热门文章

  1. Python Django Views逻辑处理 及 Urls路由规则
  2. 低电时限制USB反向充电
  3. 外贸企业收集了几十万的客户邮箱,怎么群发邮件?
  4. 手机app直播源码开发
  5. 树莓派4B--openCV简单教程及人脸识别
  6. 201819101034 田鑫萌
  7. 第三方舆情收集与质量闭环建设
  8. (转)python logging模块
  9. SD卡格式化恢复怎么操作?只用这招!
  10. 微信小程序拍照上传图片wx.getImageInfo()获取图片信息