Java虚拟机-JVM

Java 虚拟机(JVM)是什么 Java 虚拟机(JVM)是一个全面的信息处理和分析系统,集成了各种 Java 技术和工具的系统平台,能够运行 Java 字节码,从而为 Java 程序提供一个运行环境。JVM 是一个虚构出来的计算机,它是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。Java 虚拟机就是典型的程序虚拟机,它专门为执行单个计算机程序而设计,在 Java 虚拟机中执行的指令我们称为 Java 字节码指令。JVM 主要由类装载器、运行时数据区、执行引擎、本地接口库和本地方法库等部分组成。 阅读详情

Java内存模型

为什么说java是跨平台语言

所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行;

实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序;

这个跨平台是中间语言(JVM)实现的跨平台;

Java有JVM从软件层面屏蔽了底层硬件、指令层面的细节让他兼容各种系统;

Jdk和Jre和JVM的区别

Jdk包括了Jre和Jvm,Jre包括了Jvm;

Jdk是我们编写代码使用的开发工具包;

Jre 是Java的运行时环境,他大部分都是 C 和 C++ 语言编写的,他是我们在编译java时所需要的基础的类库;

Jvm俗称Java虚拟机,他是java运行环境的一部分,它虚构出来的一台计算机,在通过在实际的计算机上仿真模拟各种计算机功能来实现Java应用程序;

JVM由那些部分组成

JVM包含两个子系统和两个组件: 两个子系统为Class loader(类装载)、Execution engine(执行引擎);

两个组件为Runtime data area(运行时数据区jvm的内存)、Native Interface(本地接口);

运行时数据区

程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;

Java 虚拟机栈(Java Virtual Machine Stacks):每个方法在执行的同时都会在Java 虚拟机栈中创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息;

本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;

Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;

方法区(Methed Area):方法区是所有线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码的一些数据。

线程共享的:堆和方法区
线程独享的:程序计数器,java虚拟机栈,本地方法栈

什么是直接内存?
直接内存并不属于JVM的内存结构,它是物理机的内存,但是JVM虚拟机可以调用该部分内存。
我的理解就是直接内存是基于物理内存和Java虚拟机内存的中间内存

详细说一下Java虚拟机栈

1.局部变量表:是用来存储我们临时8个基本数据类型、对象引用地址、returnAddress类型;
(returnAddress中保存的是return后要执行的字节码的指令地址。)

2.操作数栈:操作数栈就是用来操作的,他在一开始的时候就会进行操作,读取我们的代码,进行计算后再放入局部变量表中去;

3.动态链接:假如我方法中,有个别的方法,需要调用这个方法,要链接到别的方法中去,这就是动态链接,存储链接的地方。

4.出口:出口是什呢,出口正常的话就是return 不正常的话就是抛出异常。

一个方法调用另一个方法,会创建很多栈帧吗?
答:会创建。如果一个栈中有动态链接调用别的方法,就会去创建新的栈帧,栈中是由顺序的,一个栈帧调用另一个栈帧,另一个栈帧就会排在调用者下面

递归的调用自己会创建很多栈帧吗?
答:递归的话也会创建多个栈帧,就是在栈中一直从上往下排下去

栈指向堆是什么意思?
答:栈指向堆是什么意思,就是栈中要使用成员变量怎么办,栈中不会存储成员变量,只会存储一个应用地址

详细介绍一下Java堆

java堆(Java Heap)是java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。

在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。

java堆是垃圾收集器管理的主要区域,因此也被成为“GC堆”。

从内存回收角度来看java堆可分为:新生代和老生代。

从内存分配的角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区。

​ 无论怎么划分,都与存放内容无关,无论哪个区域,存储的都是对象实例,进一步的划分都是为了更好的回收内存,或者更快的分配内存。

​ 根据Java虚拟机规范的规定,java堆可以处于物理上不连续的内存空间中。当前主流的虚拟机都是可扩展的(通过 -Xmx 和 -Xms 控制)。如果堆中没有内存可以完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

什么是JVM字节码执行引擎

​ 虚拟机核心的组件就是执行引擎,它负责执行虚拟机的字节码,一般户先进行编译成机器码后执行。

​ “虚拟机”是一个相对于“物理机”的概念,虚拟机的字节码是不能直接在物理机上运行的,需要JVM字节码执行引擎- 编译成机器码后才可在物理机上执行。

Java内存泄露

内存泄露:是指不再被使用的对象或者变量一直被占据在内存中。长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。

内存溢出:申请内存空间,超出最大堆内存空间。Xms:堆内存 Xmx:堆最大内存。

栈溢出堆溢出

栈内存溢出:最常见的就是递归。每次递归就相当于调用一个方法,方法每次被调用时都会在栈中创建一个栈帧。占用的内存直到整个递归结束才会被释放,在递归过程中只会累加,不会释放。所以会造成栈内存溢出。

堆内存溢出(OutOfMemoryError : java heap space):需要分清是 内存溢出 还是 内存泄漏:
(1)如果是内存溢出,则通过 调大 -Xms,-Xmx参数。
(2)如果是内存泄露,则看对象如何被 GC Root 引用。

垃圾回收机制和算法

Java垃圾回收机制

​ 在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

Java垃圾回收分为两步:
一、标记(怎么标记看 <怎么判断对象是否可以被回收? 章节>)
二、清除(怎么清除看 <JVM垃圾回收算法> 章节)

GC是什么

GC 是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java 语言没有提供释放已分配内存的显示操作方法。

垃圾回收的优点和缺点

优点:JVM的垃圾回收器都不需要我们手动处理无引用的对象了,这个就是最大的优点
缺点:程序员不能实时的对某个对象或所有对象调用垃圾回收器进行垃圾回收

垃圾回收器的原理是什么?有什么办法手动进行垃圾回收?

对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。

​ 通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。

程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

JVM 中都有哪些引用类型?

强引用:发生 gc 的时候不会被回收。
软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
弱引用:有用但不是必须的对象,在下一次GC时会被回收。
虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,虚引用的用途是在 gc 时返回一个通知。

怎么判断对象是否可以被回收?

一般有两种方法来判断:
程序计数器:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。
缺点:对于相互引用的对象,没法进行清除。
可达性分析:从GcRoot根节点出发,然后向下标记那些直接或间接引用到的对象,形成引用链,不在引用链上的对象就会被视为垃圾。

Full GC是什么

清理整个堆空间—包括年轻代和老年代和永久代
因为Full GC是清理整个堆空间所以Full GC执行速度非常慢,在Java开发中最好保证少触发Full GC

对象什么时候可以被垃圾器回收

​ 当对象对当前使用这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。

​ 垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。

JVM垃圾回收算法

复制算法(1):将内存按照容量大小分为大小相等的两块,每次只使用一块,当一块使用完了,就将还存活的对象移到另一块上,然后在把使用过的内存空间移除;
特点:不会产生空间碎片;会造成空间浪费(因为只用到了原先内存的一半。);

标记清除法(2):第一步:利用可达性去遍历内存,把存活对象进行标记;第二步:在遍历一遍,将所有没有被标记的对象回收掉;
特点:第一是执行效率不稳定,执行效率都随对象数量增长而降低;第二是:空间的碎片化问题:标记、清除之后会产生大量不连续的内存碎片;

标记整理法(3):第一步:利用可达性去遍历内存,把存活对象和垃圾对象进行标记;第二步:将所有的存活的对象向一端移动,将边界以外的对象都回收掉;
特点:适用于存活对象多,垃圾少的情况;需要整理的过程,无空间碎片产生;

分代收集算法(4):根据内存对象的存活周期不同,将内存划分成几块,java虚拟机一般将内存分成新生代和老生代,在新生代中,有大量对象死去和少量对象存活,所以采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集;老年代中因为对象的存活率极高,没有额外的空间对他进行分配担保,所以采用标记清理或者标记整理算法进行回收;

System.gc():
Java的GC是由JVM自行调动的,在需要的时候才执行,上面的指令只是告诉JVM尽快GC一次,但是什么时候执行不一定。

新生代老年代永久代

​ 在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。而新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。

新生代中一般保存新出现的对象,所以每次垃圾收集时都发现大批对象死去,只有少量对象存活,便采用了复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

老年代中一般保存存活了很久的对象,他们存活率高、没有额外空间对它进行分配担保,就必须采用“标记-清理”或者“标记-整理”算法。

永久代:在这里都是放着一些被虚拟机加载的类信息,静态变量,常量等数据。这个区中的东西比老年代和新生代更不容易回收。

为什么大对象直接在老年代里面分配?
如果大对象直接在新生代分配就会导致 Eden 区和两个 Survivor 区之间发生大量的内存复制,造成空间浪费。

Minor GC、Major GC、Full GC是什么

Minor GC是新生代GC,指的是发生在新生代的垃圾收集动作。由于java对象大都是朝生夕死的,所以Minor GC非常频繁,一般回收速度也比较快。(一般采用复制算法回收垃圾)

Major GC是老年代GC,指的是发生在老年代的GC,通常执行Major GC会连着Minor GC一起执行。Major GC的速度要比Minor GC慢的多。(可采用标记清楚法和标记整理法)

Full GC是清理整个堆空间,包括年轻代和老年代

Minor GC、Major GC、Full GC区别及触发条件:

Minor GC 触发条件一般为:
1.eden区满时,触发MinorGC。即申请一个对象时,发现eden区不够用,则触发一次MinorGC。
2.新创建的对象大小 > Eden所剩空间时触发Minor GC
Major GC和Full GC 触发条件一般为:
1.从幸存区晋升到老年代的对象大小大于老年代剩余空间
2.MinorGC后存活的对象超过了老年代剩余空间
3.永久代空间不足
4.分配一个很大的对象的时候

为什么新生代要分Eden和两个 Survivor 区域?

​ 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。
老年代很快被填满,触发Major GC.老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多,所以需要分为Eden和Survivor。

​ Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历15次Minor GC还能在新生代中存活的对象,才会被送到老年代。

​ 设置两个Survivor区最大的好处就是解决了碎片化,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生)

Java堆老年代( Old ) 和新生代 ( Young ) 的默认比例?

​ 默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小。老年代 ( Old ) = 2/3 的堆空间大小。

​ 其中,新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,Edem 和俩个Survivor 区域比例是 = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),

​ 但是JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。

为什么要这样分代:

​ 其实主要原因就是可以根据各个年代的特点进行对象分区存储,更便于回收,采用最适当的收集算法:

​ 新生代中,每次垃圾收集时都发现大批对象死去,只有少量对象存活,便采用了复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

​ 而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须采用“标记-清理”或者“标记-整理”算法。

说一下 JVM 有哪些垃圾回收器?

Serial收集器(复制算法): 新生代单线程收集器,标记和清理都是单线程,优点是简单高效;

ParNew收集器 (复制算法): 新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;

Parallel Scavenge收集器 (复制算法): 新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景;

Serial Old收集器 (标记-整理算法): 老年代单线程收集器,Serial收集器的老年代版本;

Parallel Old收集器 (标记-整理算法): 老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本;

CMS(Concurrent Mark Sweep)收集器(标记-清除算法): 老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。

G1(Garbage First)收集器 ( 标记整理 + 复制算法来回收垃圾 ): Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。

类加载过程

加载:虚拟机把描述类的数据从Class文件加载到内存,
验证:检查加载的 class 文件的正确性,主要验证是否符合Class文件格式规范。
准备:给类中的静态变量分配内存空间,并设置类变量初始值。
解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址;
初始化:初始化阶段是执行类构造器() 方法的过程。

****方法:这不是由程序员写的,而是根据代码由javac编译器生成的。
它是由类里面所有的类变量的赋值动作和静态代码块组成的。
JVM内部会保证一个类的方法在多线程环境下被正确的加锁同步,也就是说如果多个线程同时去进行“类的初始化”,那么只有一个线程会去执行类的方法,其他的线程都要阻塞等待,直到这个线程执行完方法。然后执行完方法后,其他线程唤醒,但是不会再进入()方法。也就是说同一个加载器下,一个类型只会初始化一次。这也是为什么通过类加载器创建对象是线程安全的原因;

描述一下JVM加载Class文件的原理机制

​ Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。

类装载方式,有两种 :

1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中,

2.显式装载, 通过class.forname()等方法,显式加载需要的类

Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。

类加载器有哪些

1.启动类加载器(Bootstrap ClassLoader):这个类加载器使用C/C++语言实现,在JVM内部。用来加载Java核心类库。
2.扩展类加载器(Extension ClassLoader):父加载器是启动类加载器,它负责加载JRE的扩展目录,加载lib下面的ext子目录的类库。
3.应用程序类加载器(Application ClassLoader):父加载器是扩展类加载器,加载我们自己定义的类,他是程序中默认的加载器。
4.自定义类加载器:将所有继承抽象类ClassLoader的类加载器都划分为自定义类加载器。

什么是双亲委派模型

​ 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父加载器无法完成此加载任务,子加载器才会尝试自己去加载,如果均加载失败,就会抛出ClassNotFoundException异常,这就是双亲委派模式。

​ 即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了了时,儿子自己才想办法去完成。

优点:为了安全,避免自己写的类替换掉了java的核心类。

怎么打破双亲委派模型

打破双亲委派机制,即在类加载的时候不是传递到父类加载器中加载,而是由自己加载。
此时需要自定义一个类加载器,继承ClassLoader类,然后重写父类的findClass方法和loadClass方法。

1、自定义一个类加载器,继承ClassLoader类
2、重写findClass方法和loadClass方法

​ 这里最主要的是重写loadclass方法,因为双亲委派机制的实现都是通过这个方法实现的,先找父加载器进行加载,如果父加载器无法加载再由自己来进行加载,源码里会直接找到根加载器(启动类加载器),重写了这个方法以后就能自己定义加载的方式了。

JVM调优

常用的 JVM 调优的参数都有哪些?

-Xms:初始堆大小,JVM 启动的时候,给定堆空间大小。

-Xmx:最大堆大小,JVM 运行过程中,如果初始堆空间不足的时候,最大可以扩展到多少。

-Xmn:设置堆中年轻代大小。整个堆大小=年轻代大小+年老代大小+持久代大小。

-XX:NewSize=n 设置年轻代初始化大小大小

-XX:MaxNewSize=n 设置年轻代最大值

-XX:NewRatio=n 设置年轻代和年老代的比值。如: -XX:NewRatio=3,表示年轻代与年老代比值为 1:3,年轻代占整个年轻代+年老代和的 1/4

-XX:SurvivorRatio=n 年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。8表示两个Survivor :eden=2:8 ,即一个Survivor占年轻代的1/10,默认就为8

-Xss:设置每个线程的堆栈大小。JDK5后每个线程 Java 栈大小为 1M,以前每个线程堆栈大小为 256K。

-XX:ThreadStackSize=n 线程堆栈大小

-XX:PermSize=n 设置持久代初始值

-XX:MaxPermSize=n 设置持久代大小

-XX:MaxTenuringThreshold=n 设置年轻带垃圾对象最大年龄。如果设置为 0 的话,则年轻代对象不经过 Survivor 区,直接进入年老代。

#下面是一些不常用的

-XX:LargePageSizeInBytes=n 设置堆内存的内存页大小

-XX:+UseFastAccessorMethods 优化原始类型的getter方法性能

-XX:+DisableExplicitGC 禁止在运行期显式地调用System.gc(),默认启用

-XX:+AggressiveOpts 是否启用JVM开发团队最新的调优成果。例如编译优化,偏向锁,并行年老代收集等,jdk6纸之后默认启动

-XX:+UseBiasedLocking 是否启用偏向锁,JDK6默认启用

-Xnoclassgc 是否禁用垃圾回收

-XX:+UseThreadPriorities 使用本地线程的优先级,默认启用

…

JVM的GC收集器设置

-xx:+Use xxx GC
xxx 代表垃圾收集器名称

-XX:+UseSerialGC:设置串行收集器,年轻带收集器

-XX:+UseParNewGC:设置年轻代为并行收集。可与 CMS 收集同时使用。JDK5.0 以上,JVM 会根据系统配置自行设置,所以无需再设置此值。

-XX:+UseParallelGC:设置并行收集器,目标是目标是达到可控制的吞吐量

-XX:+UseParallelOldGC:设置并行年老代收集器,JDK6.0 支持对年老代并行收集。

-XX:+UseConcMarkSweepGC:设置年老代并发收集器

-XX:+UseG1GC:设置 G1 收集器,JDK1.9默认垃圾收集器

避免FullGc

1.Full GC:因为需要对整个堆进行回收,所以比较慢,因此应该尽可能减少Full GC的次数。

2.导致Full GC的原因:
1)年老代(Tenured)被写满:调优时尽量让对象在新生代GC时被回收、让对象在新生代多存活一段时间和不要创建过大的对象。
2)永久代Pemanet Generation空间不足:增大Perm Gen空间,避免太多静态对象,控制好新生代和旧生代的比例。
3)System.gc()被显示调用:垃圾回收不要手动触发,尽量依靠JVM自身的机制。
因为 System.gc 是一个 Full gc,所以会暂停整个进程。如果进程经常被频繁暂停,就要注意超时、并发的问题。

FullGc是怎么做到暂停进程的(stop the world)

​ Java里面的 GC 有一个重要的线程 VMThread。在 jvm里,这个线程会不断轮询它的队列,这个队列里主要是存一些 VM_operation 的动作,比如最常见的就是内存分配失败要求做 GC 操作的请求等,在对gc 这些操作执行的时候会先将其他业务线程都进入到安全点,也就是这些线程从此不再执行任何字节码指令,只有当出了安全点的时候才让他们继续执行原来的指令,因此这其实就是我们说的 stop the world(STW),整个进程相当于静止了。

Java笔记——Java虚拟机(JVM)从入门到实战_java jvm虚拟机 G1的整个堆会被划分成多个大小相等的区域,称之为区Region,区域不要求是连续的。如果所有的加载器都没加载过,就会层层向上委派查看是否加载过,如果都没加载过,就会由顶向下尝试进行加载,如果一个类加载器,发现这个类在自己的加载路径中,就会选择去加载这个类。1.可以通过调整年轻代和老年代的比例来适应不同类型的应用程序,提高内存的利用率和性能(假如用户比较多,有大量用户会在同一时段访问订单数据,如果新生代设置小,大量数据创建,会频繁发生minor GC,所以我们希望这些生命周期短的数据能在)。 阅读详情

相关推荐

避坑指南:Spring3集成OpenAPI时泛型响应失效的3种解决方案

本文深入探讨了Spring3集成OpenAPI时泛型响应失效的问题,提供了三种实用解决方案:移除@Schema注解、使用@ArraySchema包装泛型以及自定义Schema处理器。针对不同项目规模,详细分析了各方案的适用场景、优缺点及性能影响,帮助开发者高效生成准确的接口文档,提升前后端协作效率。

weixin_30839881的博客 100

深入理解Java虚拟机之【堆】

堆是Java内存管理的核心区域,一个JVM实例只存在一个堆内存,在JVM启动时被创建并确认空间大小。堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。所有的线程共享Java堆,但是可以划分线程私有的缓冲区(TLAB)堆是GC执行垃圾回收的重点区域,方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。-Xms :表示堆空间的起始内存。-Xmx:表示堆空间的最大内存。...

I wanna be myself, where I Belong. 1212

TDISP(TEE Device Interface Security Protocol)软件操作流程

/ 1. SPDM会话相关定义(🔶1-37、🔶1-187)// SPDM会话ID// AES-256-GCM加密密钥(TDISP要求)// 初始向量// 会话是否激活// 2. IDE流配置(🔶1-52、🔶1-625)// IDE流ID// 4个子流的AES密钥(覆盖所有子流类型)// 密钥是否已配置// 3. TDI状态与配置(🔶1-207、🔶1-210)TDI_CONFIG_UNLOCKED = 0, // 初始配置态。

inquisiter 1436

Java 性能优化之——大对象复用的目标和注意点

对于“大对象”的优化。“大对象”是一个泛化概念,它可能存放在 JVM 中,也可能正在网络上传输,也可能存在于数据库中 为什么大对象会影响我们的应用性能呢? 第一,大对象占用的资源多,垃圾回收器要花一部分精力去对它进行回收; 第二,大对象在不同的设备之间交换,会耗费网络流量,以及昂贵的 I/O; 第三,对大对象的解析和处理操作是耗时的,对象职责不聚焦,就会承担额外的性能开销 结合缓存,以及对象的池化操作,加上对一些中间结果的保存,我们能够对大对象进行初步的提速,但这还远远

vincent_wen0766的博客 3889

基于ST32 DAC7311数模转换器驱动代码及电路设计完整版

基于ST32的DAC7311模数转换器的电路设计及驱动代码完整版

qq_39626643的博客 3721

Label Studio + SAM2分割半自动标注与yolo11训练

Label Studio + SAM2分割半自动标注与yolo11训练

schFallingCloud 1408

JavaGC触发条件及优化方法

了解GC的触发条件,以及采取相应的优化方法,可以有效减少GC的频率和回收的时间,提升程序的性能。在方法内部,尽量使用局部变量而非成员变量,因为局部变量的作用域仅限于该方法,方法结束后,局部变量会在栈上被自动回收。但由于finalize方法的执行是由JVM来决定的,不确定性较大,所以在实际开发中,最好不要过度依赖该方法。这种情况下,GC的触发条件可以说是由程序的执行情况决定的。尽量避免在方法内频繁创建大量临时对象,特别是循环内部的对象创建,可以将对象的创建提到循环外部,重复利用对象,减少垃圾的产生。

wodianping的博客 1171

Linux-VMware安装后没有虚拟网卡VMnet1和VMnet8(亲测有效,一步一步跟着绝对成功)

VMware-安装后没有虚拟网卡VMnet1和VMnet8 就这个破东西我昨天弄了一天,网上什么VMware卸载重装,用CCleaner清理注册表什么的操作我全用了,但是昨天就是弄不好,同样的操作我昨天试了无数遍一直觉得可能是 持续更新中… 文章参考学习地址:https://blog.youkuaiyun.com/qq_42445139/article/details/87872130 ...

杨的博客 8852

GC触发条件

GC的触发条件一.Minor GC触发条件二.Full GC触发条件 一.Minor GC触发条件 当Eden区满时,触发Minor GC 二.Full GC触发条件 调用System.gc时,系统建议执行Full GC,但是不必然执行 老年代空间不足 方法区空间不足 通过Minor GC后进入老年代的平均大小大于老年代的可用内存 由Eden区、From Space区向To Space区复制...

sinat_18296421的博客 351

【转载】参数估计(Parameter Estimation):频率学派(最大似然估计MLE、最大后验估计MAP)与贝叶斯学派(贝叶斯估计BPE)

基础 频率学派与贝叶斯学派 http://www.douban.com/group/topic/16719644/ http://www.zhihu.com/question/20587681 最大似然估计(Maximum likelihood estimation,MLE) http://baike.baidu.com/view/1918804.htm http://baike.baidu.co

影 的专栏 3413

【MATLAB】工业传送带速度闭环控制与张力联合仿真

本文基于MATLAB/Simulink平台,构建了工业传送带速度闭环控制与张力联合仿真系统。通过搭建驱动模块、机械传动模块、检测模块和控制模块,实现了速度与张力的协同控制。采用双PID调节器分别整定速度与张力参数,经联合调试后系统性能良好:速度跟踪误差小于±0.03m/s,张力波动控制在±30N内,负载扰动恢复时间仅0.3秒。研究提供了从建模到参数优化的完整工程方案,可直接应用于课程设计或工业实践,有效解决了传送带运行中速度偏差与张力波动的协同控制难题。

unber的博客 80

gc的意义和触发条件

jvm学习随手记录,介绍关于jvm的集中普遍的清理策略

qq_43662627的博客 785

delphi 调用deepseek r1 api 并流式返回结果

摘要:本文展示了一个使用Delphi调用DeepSeek API的代码示例,包含两种调用方式:一次性获取结果和流式返回结果。代码实现了完整的API请求处理,包括HTTP客户端设置、JSON数据处理和UI界面交互。其中流式调用通过TStreamReader处理服务器发送事件(SSE),实时更新到TRichEdit控件并保持滚动条位置。文章还提到界面美化优化,为Delphi开发者提供了调用AI服务的实用参考方案。(150字)

全粘工程师 502

JVM——Java虚拟机架构

0. 前言 Java虚拟机(Java virtualmachine)实现了Java语言最重要的特征:即平台无关性。 平台无关性原理:编译后的Java程序(.class文件)由JVM执行。JVM屏蔽了与具体平台相关的信息,使程序可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。因此实现Java平台无关性。 1. JVM结构图 ...

关于Android开发的一些技术点总结 ╮( ̄▽ ̄”)╭ 3万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

【jvm系列-01】初识虚拟机与java虚拟机

为了解决java的跨平台性问题,

zhenghuishengq的博客 9757

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

java虚拟机jvm下载_Java虚拟机(JVM)简介

java虚拟机jvm下载什么是JVM Java虚拟机(JVM)是使计算机能够运行Java程序的抽象计算机。 JVM有三个概念: 1.规格 2.实施 3.实例。 该规范是正式描述JVM实现要求的文档。 具有单一规范可确保所有实现都可互操作。 JVM实现是满足JVM规范要求的计算机程序。 JVM的实例是在进程中运行的实现,该进程执行编译为Java字节码的计算机程序。 Java运行时环境(JR...

cunhui1209的博客 1119

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

JVM学习 认识java虚拟机

学习JVM之前对它的认识: 在高级语言被计算机认知并给出响应的过程中:通常是需要将高级语言由识别它们的解释编译器将他们翻译成汇编语言文件,计算机操作系统可以通过相应的编译器识别汇编语言从而将其转换为01组合的机器指令,这些指令是可以被CPU识别并作出相应操作的。 jvm虚拟机在对比计算机操作系统层面来讲,相当于一个针对java编译与运行的环境搭建的软件。它相当于计算机操作系统层面的一个只针对与java语言的虚拟的计算机软件。它的垃圾回收算法其实与操作系统中的外部/内部碎片回收也有一定的相似性。对于一个只

m0_59588838的博客 1498

【Java 基础(人话版)】Java 虚拟机(JVM)

它负责把 Java 代码转换成计算机能识别的机器语言,并且让不同操作系统上的 Java 程序表现一致。JVM 负责运行 Java 代码,使得 Java 具有良好的跨平台能力。,都能保证相同的 Java 代码在不同平台上运行时,结果是一致的。不同 JVM 各有特点,适用于不同的场景。只是 JVM 规范的一种实现方式,除此之外,还有。,任何公司、组织甚至个人都可以实现自己的 JVM。JVM 运行时会划分出不同的内存区域,用来存储。等不同系统,所有 JVM 只要遵循相同的。不同 JVM 适用于不同场景,例如。

qq_45729306的博客 1万+

Java虚拟机JVM简介与理解(一)

Java虚拟机JVM简介与理解(一)

cucgyfjklx的博客 1万+

Java中JVM虚拟机详解

1、 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

HuangQinJian 3万+

Java虚拟机(JVM 虚拟机)

所谓虚拟机,就是一台虚拟的计算机。他是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。大名鼎鼎的 VisualBox、VMware就属于系统虚拟机。他们完全是对物理计算机的仿真。提供了一个可以运行完整操作系统的软件平台。程序虚拟机的典型代表就是Java虚拟机,它专门为执行单个计算机程序而设计,在Java虚拟机中执行的指令我们称为Java字节码指令。

m0_74201628的博客 964

java虚拟机jvm

java虚拟机jvm -生命周期结束 1.执行System.exit()方法 2.程序正常执行结束 3.程序在执行过程中遇到异常或因错误而抛异常终止 4.由于操作系统出现错误而导致java虚拟机进程终止 -执行流程 加载:查找并加载类的二进制数据 连接: 验证被加载类的正确性 准备为类的静态变量分配内存,并将其初始化为默认值 解析将类中的符号引用,转换为直接引用 初始化:为静态变量赋值正确的...

weixin_34324081的博客 227

JVM_Java虚拟机<深入理解Java虚拟机>走进JVM

由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。时至今日,尽管嵌入式平台已经不是Java程序的主流运行平台了(准确来说应该是HotSpotVM的宿主环境已经不局限于嵌入式平台了),那么为什么不将架构更换为基于寄存器的架构呢?栈:跨平台性、指令集小、指令多、执行性能比寄存器差言包括:Java、Scala、Groovy、Kotlin;

Coastlise的博客 1168

【JVM】JAVA虚拟机总结(一)——什么是JVM

前言:Java语言里负责解释执行字节码文件的是Java虚拟机,即JVM——Java Virtual Machine(Java虚拟机)。执行Java程序的两个步骤:由Java语言编写的程序需要进过编译步骤,但这个编译步骤并不会生成特定平台的机器码,而是生成一种与平台无关的字节码(*.class文件)。这种字节码不是可执行的,必须使用Java解释器来解释执行。所有Java语言既不是纯粹的编译型语言,也...

一路向前! 4746

Java虚拟机 (JVM)(1) —— 初识JVM

Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。JVM是java虚拟机,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。

知唔猪的博客 1025
上一篇: hexo部署到服务器之后图片无法访问问题
JiangPengCode
博客等级 码龄6年 2粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JiangPengCode

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值