首页 > 其他分享 >关于 JVM

关于 JVM

时间:2024-06-01 20:59:03浏览次数:21  
标签:对象 关于 线程 引用 JVM 加载 内存

内存区域划分

        像办公楼一样,有办公区休息区吃饭区啥的,JVM 这个应用程序就会在启动的时候就会向操作系统申请一块内存区域,然后把这个区域分成几个部分,每个部分有不同的功能作用。一个 Java 进程就对应一个 JVM。

(虽然说这里的栈也是“先进后出”的,但数据结构的栈是个更大的概念,这里的特指 JVM 的一块内存空间)

本地方法栈(线程私有):native 表示 JVM 内部的 C++ 代码,这里就是给调用 native 方法(JVM 内部的方法)准备的栈空间。这里存储的是 native 方法之间的调用关系。

程序计数器(线程私有): 记录当前线程执行到哪个指令了。每个线程一份,很小一块存一个地址的。

虚拟机栈(线程私有):给 Java 代码使用的栈,这里面拥有很多个栈,每个线程就对应一个。这里存储的是 方法 之间的调用关系。每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。调用一个方法就创建一个栈帧。

堆区(线程共享):整个 JVM 空间最大的区域,new 出来的对象(类的成员变量)都在堆上。一个进程只有一个堆。

元数据区 / 方法区(线程共享):用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据的。运行时常量池是方法区的一部分,存放字面量与符号引用。字面量 : 字符串(JDK 8 移动到堆中) 、final常量、基本数据类型的值。 符号引用 : 类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。

小结:1. 局部变量在 栈 上、2. 普通成员变量在 堆 上、3. 静态成员变量在 方法区。

类加载

        类加载就是将 .class 文件 从文件(硬盘)被加载到内存中(元数据区)的过程。

加载:就是把 .class文件先找到(找的过程)然后打开文件读文件,再把文件内容读到内存中。最终加载完成得到了一个类对象。

验证:根据 JVM 虚拟机规范来检查 .class 文件格式(是一个二进制文件)是否正确。

准备:给类对象分配内存空间(先在元数据区占个位置),同时也会使静态成员被设置成 0 值。

解析:初始化字符串,把符号引用转为直接引用。字符串常量得有一块内存空间来存,这块内存空间还得有一个引用来保存内存空间的起始地址,当类加载的时候,字符串常量处在 .class文件 中,此时这个引用记录的并非字符串常量真实的地址(占位符),此时就是符号引用;当类加载之后,字符串常量真正被放到内存中了,此时才有内存地址,这个引用才能被真正赋值成内存地址,此时就是直接引用了。

初始化:调用构造方法,进行成员初始化,执行代码块,静态代码块,加载父类......

 一个类,什么时候会被加载?要用到的时候才加载,加载过一次之后就不用重复加载了。

1. 构造 类 的实例大的时候

2. 调用这个类的 静态方法/使用静态属性

3. 加载子类的时候会先加载其父类

双亲委派模型

        双亲委派模型描述的是在加载中,找 .class 文件的基本过程。

        类加载器工作流程:首先加载一个类的时候,是从 ApplicationClassLoader开始的,但是它会把加载人物交给父亲去加载,到了ExtensionClassLoader这里它也会交给父亲去加载,到了BootstrapClassLoader之后,再想交给父亲发现没有上级了,就只能自己加载了,搜索自己负责的标准库目录相关的类,找到就加载,没找到就继续传回去由子类来加载。如果最下面的还没找到这个类那么就会抛异常了。 

        为啥有这顺序: 主要是出自于 JVM 实现代码的逻辑,因为 JVM 的代码是按照类似于递归的方式来实现的。同时,这个顺序也保证了 Bootstrap 能先加载,Application 能后加载,这就能避免程序猿定义了一个类似于 java.lang.String 这样的类,就会先加载的是标准库的类而不会加载到自己写的这个类了。再者,也可以自定义类加载器,自定义的能随便加入上述流程的任意位置。

垃圾回收机制

        所谓的“垃圾”,指的就是不再使用的内存,垃圾回收就是把不用的内存帮我们自动释放了。(C++是要自己手动释放的,否则可能会出现“内存泄漏问题”)

GC

        GC 是当下最主流的一种垃圾回收机制。上面已经知道,JVM 里是有很多的内存区域的,GC 主要就是针对 堆 进行释放的,因为大,多。同时,GC 是以“对象”为基本单位进行回收的,为不是字节,比如一个对象有很多属性,其中7个不用了,3个还在用,那么此时就不会回收那不用的7个,而是都不用了才把这个对象一起回收。

GC 实际工作过程

1. 找到垃圾 / 判定垃圾

        关键思路,就是看这个对象有没有“引用”在指向它。这里有两种方式判断:

a)引用计数【python、php......】

        会给每个对象分配一个计数器,每当创建一个引用的时候计数器就+1,当这个引用被销毁了计数器就-1。虽然这个方法简单有效,但是存在两个问题:第一个内存空间浪费多,因为计数器也是需要一定内存来存数据的,当代码中存在多个对象的时候就会额外产生很多内存占用。第二个就是存在循环引用问题:

b)可达性分析【Java的做法】

        Java 的对象都是通过引用来指向并访问的,大多数情况下,一个引用指向一个对象,这个对象里面的成员又指向别的对象,比如二叉树。然后可达性分析,就把所有的这些对象组织的结构视为是树,然后就从树结点出发,遍历这棵树,把可以访问的视为“可达”,不能访问的视为“不可达”。JVM 就会将这些不可达的视为垃圾进行回收。很明显,这种遍历相比上述会比较慢,因此就会隔一段时间遍历一遍。

2. 再以对象为单位进行释放
垃圾回收算法
a)标记清除

b)复制算法(解决了内存碎片问题)

c)标记整理(解决了复制算法空间利用率低的缺点)

这种类似于顺序表有搬运元素的操作,效率也不高,特别是当搬运空间比较大的时候开销也会更大。

分代回收

        基于上述这些基本策略,JVM 就采用了复合策略,也就是把垃圾回收分成不同的场景,根据场景的不同决定使用哪些算法。

        这里就会给对象引入一个 “年龄” 这样的概念,其中的 “一岁” 就代表经历了一轮可达性分析之后,发现这个对象不是垃圾(也可以理解成是 熬过GC的轮次)。

标签:对象,关于,线程,引用,JVM,加载,内存
From: https://blog.csdn.net/weixin_43497876/article/details/139239051

相关文章

  • 一文了解JVM面试篇(上)
     Java内存区域1、如何解释Java堆空间及GC?当通过Java命令启动Java进程的时候,会为它分配内存。内存的一部分用于创建堆空间,当程序中创建对象的时候,就从对空间中分配内存。GC是JVM内部的一个进程,回收无效对象的内存用于将来的分配。2、JVM的主要组成部分及......
  • 关于css预处理器sass详解
    Sass(SyntacticallyAwesomeStylesheets)是一种强大的CSS预处理器,旨在简化CSS的编写并增强其功能。以下是对Sass的详细解释,包括其特点、功能、语法格式以及使用方式。1.Sass的特点扩展CSS功能:Sass在CSS的基础上增加了变量、嵌套、混合(mixins)、继承等高级功能,使得CSS的编......
  • 关于最新版本protobuf在Windows环境下编译失败的解决办法
    在最新版本的cmake子目录中你是看不到CMakeLists.txt文件的,所以你会遇到莫名其妙的错误。经过长时间的摸索,得出一条稳妥的解决方案:参考以下视频的protobuf版本10.在widnows中编译和部署protobuf_哔哩哔哩_bilibili即可成功。。。没必要给自己找事做.点击跳转protobuf3.......
  • 一文了解JVM面试篇(上)
    Java内存区域1、如何解释Java堆空间及GC?当通过Java命令启动Java进程的时候,会为它分配内存。内存的一部分用于创建堆空间,当程序中创建对象的时候,就从对空间中分配内存。GC是JVM内部的一个进程,回收无效对象的内存用于将来的分配。2、JVM的主要组成部分及其作用?组......
  • 关于Camunda
    Camunda事务编排平台,交付形态有saas和public/privatecloud方式,通过UI可以编排基于bpmn和dmn文件格式的业务流文件,业务流(process)通过生成task的方式根据用户输入的参数和预定义的流程完成一系列复杂的任务。https://github.com/zongzw-learn/learn-camunda.git以上代码中,使用go......
  • 关于GOGC的几点认识
    以下理解来自https://tip.golang.org/doc/gc-guide文章并不好理解。。go的标准库runtime提供了GC的相关能力。栈上的空间不归GOGC管,GOGC只考虑heap空间。所谓的transitive性质:部分衍生空间会纳入到GOGC回收中。GOGC使用tracinggarbagecollection的方式。GC需要关注的......
  • 关于高并发下的数据处理
    架构总是在不断修正演变的过程中得到完善!!!需求背景:接到了一个判断报文中规则来触发告警的需求,本以为需求很简单,具体的告警逻辑就不赘述了,大体的流程是:接收到报文,报文中有定义规则和对应的当前值,判断当前值是否需要触发告警,如果需要则触发告警,存储告警,通过mqtt推送告警信息给前端......
  • 关于12306技术相关说明以及暂定计划
    12306项目中包含了缓存、消息队列、分库分表、设计模式等代码,通过这些代码可以全面了解分布式系统的核心知识点。在系统设计中,采用最新JDK17+SpringBoot3&SpringCloud微服务架构,构建高并发、大数据量下仍然能提供高效可靠的12306购票服务。下方的架构图全面描述了项......
  • 关于一道高斯函数题目
    令\(\lfloorx\rfloor\)为不大于\(x\)的最大整数。\(\{x\}=x-\lfloorx\rfloor\)。题目1题面求值:\[\sum\limits_{i=1}^{2015}\left\{\frac{2015i}{2016}\right\}\]标准答案\[\begin{aligned}&\left\{\frac{2015i}{2016}\right\}\\......
  • 机器学习——关于SVM的些许问题的个人思考
    最近在利用python对机器学习进行实践,因为之前我是先完整的刷了一遍周志华老师的《西瓜书》才开始的实践活动,因此,时间跨度很久,以至于对于SVM的相关理论有些生疏了,甚至关于SVM的一些之前没注意到的问题,现在暴露了出来,所以这篇文章主要是想跟大家分享一下个人关于SVM的一些令人纠......