Java 架构知识

Java 架构知识

时间:2021年3月24日13:53:07

JVM

基本概念

JVM 是可运行 Java 代码的假象计算机

JVM = 一套字节码指令集 + 一组寄存器 + 一个栈 + 一个堆 + 一个方法区

JVM 是运行在 OS 上的,与硬件没有直接交互

运行过程

  1. Java 源代码 ---> 编译器 ---> 字节码文件
  2. 字节码文件 ---> JVM ---> 机器码

每一种平台的解释器是不同的,但是实现的虚拟机是相同的,也就是为什么 Java 能够跨平台的原因

JVM 内存模型

image-20210324135735409

线程

线程:程序执行过程中的一个线程实体

JVM 允许一个应用并发执行多个线程

Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关系

当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统功能原生线程。

Java 线程结束,原生线程随之被回收。操纵系统负责调度所有线程,并把它们分配到任何可用的 CPU 上。当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。当线程结束时,会释放原生线程和 Java 线程的所有资源

Hotspot JVM 后台运行的系统线程主要有下面几个:

线程名描述
VM 线程JVM到达安全点操作出现。这些操作必须要在独立的线程里执行(stop-the-world垃圾回收,线程栈 dump,线程暂停,线程偏向锁解除
周期性任务线程负责定时器时间(即中断),用来调度周期性操作的执行
GC 线程支持 JVm 中不同的垃圾回收活动
编译器线程在运行时将字节码动态编译成本地平台相关的机器码
信号分发线程接收发送到 JVM 的信号并调用适当的 JVM 方法处理

JVM 内存区域

image-20210324141819184

JVM 内存区域

  • 线程私有区域:程序计数器,虚拟机栈,本地方法区(生命周期与线程相同)
  • 线程共享区:Java 堆,方法区(生命周期和 JVM 相同)
  • 直接内存:不是 JVM 运行时数据区的一部分,但也会被频繁使用

image-20210324142541756

程序计数器

是当前线程所执行的字节码的行号指示器

唯一一个在虚拟机中没有规定任何 OOMError 情况的区域

  • 虚拟机字节码指令地址(Java 方法)
  • 空(Native 方法)

虚拟机栈

描述 Java 方法执行的内存模型

每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口灯信息

每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程

  • 栈帧:是用来存储数据和部分过程结果的数据结构,也被用来处理动态链接、方法返回值和异常分配。栈帧随着方法调用而创建,随着方法结束而销毁

image-20210324143212632

本地方法区

和 Java Stack 作用类似

虚拟机栈为执行 Java 方法服务,而本地方法栈是为 Native 方法服务

是被线程共享的一块内存区域,创建的对象和数组都保存在 Java 对内存中,也是来及收集器进行垃圾收集的最重要的内存区域。由于现代 JVM 采用分代收集算法,因此 Java 堆从 GC 的角度还可以细分为:新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代

方法区

用来存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码

  • 运行时常量池:用于存放编译器生成的各种字面量和符号引用

JVM 运行时内存

GC 的角度还可以细分为:新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代image-20210324144003581

新生代

用来存放新生的对象。一般占据对的 1/3 空间。由于频繁创建对象,所以新生代会频繁触发 MinorGC 进行垃圾回收。

  • Eden 区:Java 新对象出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当 Eden 区内存不足时就会触发 MinorGC,对新生代区进行一次垃圾回收
  • Survivor From 区:上一次 GC 的幸存者,作为这一次 GC 的被扫描者
  • Survivor To 区:保留了一次 MinorGC过程的幸存者

MinorGC 的过程

复制 ---> 清除 ---> 互换

  1. eden和 survivor from 复制到 survivor to 区,年龄 +1
  2. 清空 eden 和 survivor from
  3. survivor from 和 survivor to 互换

老年代

主要用来存放应用程序中生命周期长的对象

  • 在 MajorGC 前一般会进行一次 MinorGC

MajorGC 采用 标记-清除算法

标记处存活的对象,如何回收没有被标记的对象

方法区

JDK7的永久代变为JDK的元空间

二者区别:元空间并不在虚拟机找那个,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制

字符串池和类的静态变量放入 Java 堆中

类的元数据放入本地内存

垃圾回收与算法

image-20210324145410105

如何确定垃圾

  • 引用计数法:对象引用数量统计,引用计数为0则可回收。存在循环引用问题
  • 可达性分析:通过一些列 “GC Root”对象作为起点搜索。不可达对象不等于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍是可回收对象则将面临回收

标记-清除算法

两阶段

  • 标记:标记处所有需要回收的对象
  • 清除:清除被标记的对象所占用的内存空间

image-20210324150102180

存在问题

  • 内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题

复制算法

为了解决标记-清除算法带来的内存碎片化问题

将内存容量划分为等大小的两块,每次只使用其中一块,当这一块内存满后将仍存活的对象复制到另一块,把已使用的内存清理

image-20210324150405835

存在问题

  • 可用内存被压缩到原来的一半,且存活对象增多的话,复制算法的效率大大降低

标记-整理算法

结合以上两个算法

  1. 标记:同 标记-清除算法第一步
  2. 整理:架构存活对象移向内存一端
  3. 清除:清除端边界外的对象

image-20210324150628633

分代收集算法

目前大部分 JVM 都是使用此算法

核心:根据对象存活的不同生命周期将内存划分为不同的域

老年代:每次垃圾回收时只有少量对象需要被回收

新生代:相反

  • 新生代:通常使用 复制算法image-20210324151108915

  • 老年代:通常使用 标记-整理算法'

总结

  1. 方法区用来存储 class 类,常量,方法描述等。对方法区回收主要包括废弃常量和无用的类
  2. 对象的内存分配主要是在新生代,少数情况直接分配到老年代
  3. 当新生代的 Eden 区和 From 区空间不足时就会发生一次 GC,进行 GC 后,Eden 区和 From 区的存活对象会被挪到 To 区,如何将 Eden 区和 From 区进行清理
  4. 如果 To 区无法存储某个对象,则将这个对象存储到老年代
  5. 当对象在 Survivor 区躲过一次 GC 后,其年龄就会 +1,默认情况下年龄到达 15 的对象会被移到老年代

Java 四种引用类型

强引用

通过 new 关键字创建的对象引用

软引用

需要用 SoftReference 类实现

当系统内存足够时他不会被回收,当系统内存不足时,会被回收。软引用通常在对内存敏感的程序中

弱引用

需要用 WeakReference 类实现

比软引用生存期更短

只要进行一次 GC,不管 JVM 内存空间是否足够,软引用类型对象将被回收

虚引用

需要用 PhantomReference 类实现

不能单独使用,必须和引用队列联合使用

主要作用是跟踪对象呗垃圾回收的状态

分区收集算法

将整个堆空间划分为连续的不同大小区间,独立回收,这样的好处是可以控制一次回收多少个小区间,根据目标停顿时间,每次合理地回收若干个小区间(而不是整个堆),从而减少一次 GC 所产生的停顿

GC 垃圾收集器

Java 集合

Java 多线程

Java 基础

Spring 原理

微服务

Netty 与 RPC

网络

日志

Zookeeper

Kafka

RabbitMQ

Hbase

MongoDB

Cassandra

设计模式

负载均衡

数据库

一致性算法

Java 算法

数据结构

加密算法

分布式缓存

Hadoop

Spark

Storm

YARN

机器学习

云计算

# java  架构 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×