JVM结构化体系

news2024/11/27 3:47:12

目录

目录

1.JVM 简介

1.1. 如何理解 JVM 呢?

 1.2. 市场主流 JVM 分析?

1.3. 为什么要学习 JVM?

1.4. 字节码底层是如何执行呢?

如何理解 JIT 呢?

为什么 JVM 中解释执行与编译执行的并存(混合模式)?

1.5. 如何理解 JVM 的运行模式?

如何查看现在 JVM 的工作模式?

2.JVM 体系结构

2.1. JVM 的产品架构是怎样的?

2.2. JVM 运行时内存结构是怎样的?

2.2.1. JVM 线程共享区应用分析

1. Heap (堆内存):

2. Method Area (方法区)

2.2.2. JVM 线程私有区应用分析

1. Program Counter Register (程序计数器)

2. Stack Area (虚拟机栈区)

3. Native Stack Area (本地方法栈)

 3.JVM 应用参数分析

3.1. 如何理解 JVM 中的内存溢出?

代码演示:堆内存溢出

代码演示:元数据内存溢出(JDK8)

3.2. JVM 工具应用分析篇

3.2.1. 命令行工具篇

1. Jps [options] [hostid] (hostid 为 ip 或域名地址)

2. jmap -heap pid

3. jstack 用于生成 java 虚拟机当前时刻的线程快照


1.JVM 简介

1.1. 如何理解 JVM 呢?

JVM(Java Virtual Machine) 是:
1) JAVA 平台的一部分,是一种能够运行 Java bytecode 的虚拟机。
2) 是硬件计算机的抽象 ( 虚构 ) 实现,可以解释执行 JAVA 字节码。
3) 是实现 JAVA 跨平台运行的基石。

 1.2. 市场主流 JVM 分析?

JVM 是一种规范基于这种规范,不同公司就对此规范做了具体实现,例如市场上
的一些主流 JVM 如下:
1. JRockit VM (BEA 公司研发,后在 2008 年由 Oracle 公司收购 )
2. HotSpot VM (Sun 公司研发,后在 2010 年由 Oracle 公司收购 )
3. J9 VM IBM 内部使用)
说明: HotSpot 目前是应用最官方,最主要的一款 JVM 虚拟机

1.3. 为什么要学习 JVM

深入理解 JVM 可以帮助我们从平台角度提高解决问题的能力,例如:
1) 有效防止内存泄漏( Memory leak
2) 优化线程锁的使用 (Thread Lock) 齐雷 qilei@tedu.cn
1-4
3) 科学进行垃圾回收 (Garbage collection)
4) 提高系统吞吐量 (throughput)
5) 降低延迟 (Delay) ,提高其性能 (performance)

1.4. 字节码底层是如何执行呢?

JAVA 源程序编译,执行过程如下图所示:

在主流的 JVM (例如 HotSpot )中 , class 文件翻译成机器码执行时提供了两
种方式,如下图所示:1
其中:
1) 热点代码: 一般泛指循环或高频使用的方法。
2) 解释执行器:负责逐条将字节码翻译成机器码并执行。
3) 编译执行器:负责即时编译 (Just-In-Time compilation,JIT) 执行。

如何理解 JIT 呢?

JIT( 即时编译 ) 是用来提高 java 程序运行效率的一种技术 , 基于这种技术,可以
字节码编译成平台相关的原生机器码,并进行各个层次的优化,这些机器码会被
缓存起来,以备下次使用。

为什么 JVM 中解释执行与编译执行的并存(混合模式)?

解释器与编译器两者各有优势,当程序需要迅速启动和执行的时候,解释器可以
首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,
即时编译( JIT )逐渐发挥作用,它可以对反复执行的热点代码以方法为单位进
行即时编译,可以获取更高的执行效率。但是如果 JIT 对每条字节码都进行编
译,缓存 ( 缓存的指令是有限的 ) ,会增加开销。所以当程序运行环境中内存资源
限制较大(如部分嵌入式系统中),可以使用解释器执行节约内存,反之可以使
用编译执行来提升效率。

1.5. 如何理解 JVM 的运行模式?

JVM 有两种运行模式 Server Client。两种模式的区别在于,Client

式启动速度较快, Server 模式启动较慢;但是启动进入稳定期之后 Server
式的程序运行速度比 Client 要快很多。这是因为 Server 模式启动的 JVM 采用
的是重量级的虚拟机,对程序采用了更多的优化;而 Client 模式启动的 JVM
用的是轻量级的虚拟机。所以 Server 启动慢,但稳定后速度比 Client 远远要
快。

如何查看现在 JVM 的工作模式?

说明:现在 64 位的 jdk 中默认都是 server 模式。当虚拟机运行在 -client
模式的时候 , 使用的是一个代号为 C1 的轻量级编译器 , -server 模式启动的
虚拟机采用相对重量级 , 代号为 C2 的编译器 .c1 c2 都是 JIT 编译器, C2 C1 编译器编译的相对彻底 , 服务起来之后 , 性能更高 .

2.JVM 体系结构

2.1. JVM 的产品架构是怎样的?

JVM Java Hotspot Architecture :主要分为三大部分:
1) 类加载系统 ( ClassLoader System ) :负责加载类到内存
2) 运行时数据区 ( Runtime Data Area ):负责存储数据信息
3) 执行引擎 ( Execution Engine : 负责调用对象执行业务

2.2. JVM 运行时内存结构是怎样的?

JVM 启动运行 Class 文件时会对 JVM 内存进行切分,我们可以将其分为线程共

享区和线程独享区。如下图所示 .
其运行时内存详细架构如下:
备注:
 
1.在 JDK8 中持久代 (Permanent Generation)部分数据移到了元数据 ( Metaspace ),在 JDK8 中已经没有持久代。元空间的本质和永久代类似,都   JVM 规范中方法区的实现,不过元空间与永久代之间最大的区别在于:元空 间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受 本地内存限制,但可以通过以下参数来指定元空间的大小。

2.永久代

在自定义类加载器还不是很常见的时候,类大多是static的,很少被卸载或收集,因此被成为“永久的(Permanent)”。

同时,由于类class是JVM实现的一部分,并不是由应用创建的,所以又被认为是“非堆(Non-Heap)”内存。

在JDK8之前的HotSpot JVM,存放这些“永久的”区域叫做“永久代(permanent generation)”。

2.2.1. JVM 线程共享区应用分析

1. Heap (堆内存)
堆内存概要:
1) 虚拟机启动时创建,被所有线程共享 , 用于存放所有 java 对象实例 .
2) 可分为年轻代 (eden) 和老年代 (Tenured)
3) 是垃圾收集器(GC)管理的主要区域
4) 堆中没有内存分配时将会抛出 OutOfMemoryError
对象在内存中分配说明:
新创建的对象一般都分配在年轻代,当对象比较大时年轻代没有足够空间存储时还可直接分配到老年代。 有时候系统为了减少 GC 开销对于小对象且没有逃逸的对象还 可以直接在栈上分配。
堆内存大小配置参数说明:
1) -Xms 设置堆的最小空间大小。
2) -Xmx 设置堆的最大空间大小。
3) -XX:NewSize 设置新生代最小空间大小。
4) -XX:MaxNewSize 设置新生代最大空间大小。
5) -XX:NewRatio 新生代和老年代的比值,值为 4 则表示新生代 : 比老年代 1: 4
6) -XX:SurivorRatio 表示 Survivor eden 的比值,值为 8 表示两个 survivor:eden=2:8.
8) -Xss: 设置每个线程的堆栈大小。
2. Method Area (方法区)
方法区(1.8以后叫元数据区)概要:
1) 非堆内存,逻辑上的定义, 用于存储类的数据结构信息,常量、静态变量以及即时编译器编译后的代码等数据。
由于元 数据存储的信息不容易变动,因此它被安置在一块堆外内存。
2) 不同 jdk ,方法区的实现不同, JDK8(hotspot)  中的方法区对应的是 Metaspace,是一 块本地内存。
方法存储说明: 
方法区内存配置参数说明:
1) -XX:PermSize 设置永久代最小空间大小( JDK8 已弃用)。
2) -XX:MaxPermSize 设置永久代最大空间大小( JDK8 已弃用)。
3) -XX:MetaspaceSize 设置元数据区最小空间。 (JDK8)
4) -XX:MaxMetaspaceSize 设置元数据区最大空间。 (JDK8)

2.2.2. JVM 线程私有区应用分析

1. Program Counter Register (程序计数器)
1) 线程启动时创建,线程私有。
2) 用于记录当前正在执行的程序的字节码指令地址
3) Java 虚拟机规范唯一一个没有内存溢出的区域。
2. Stack Area (虚拟机栈区)
虚拟机栈概要:
1) 用于存储栈帧 (Stack Frame) 对象,保存方法的局部变量表操作数
行运行时常量池的引用一些额外的附加信息
2)每  一次方法调用都会创建一个新的栈帧,并压栈。当方法执行完毕之后,便会
将栈帧出栈。
3) 栈上对象的分配:对于小对象(一般几十个 bytes ),在没有逃逸的情况下,可以
直接分配在栈上(直接分配在栈上,可以自动回收,减轻 GC 压力);大对象
或者逃逸对象无法栈上分配
说明:方法在进行递归调用时容易出现栈内存溢出。
虚拟机栈参数说明:
1 -Xss128k : 设置每个线程的栈大小
JDK5.0 以后每个线程堆栈大小为 1M ,以前每个线程堆栈大小为 256K。可根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多 的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经 验值在 3000~5000 左右。
3. Native Stack Area (本地方法栈)

1) 为虚拟机使用到的 Native 方法提供服务。
2) 用于存储本地方法执行时的一些变量信息,操作数信息,结果信息。

 3.JVM 应用参数分析

3.1. 如何理解 JVM 中的内存溢出?

每个 Java 程序运行时都会使用一定量的内存 , JVM 内存不足以满足当前 java 程序运行时所需要的内存资源时就会出现内存溢出的现象。

代码演示:堆内存溢出

在如下代码中假如不断的向 list 集合中存储新的对象,list 集合底层也会不 断的进行扩容,当内存中没有足够连续内存 空间存储这些对象时就会出现堆内 存溢出。
 
public class TestOOM01 {
    public static void main(String[] args) {
        long t1=System.currentTimeMillis();
        try {
            List<byte[]> list=new ArrayList<>();
            for(int i=0;i<100;i++) {
                list.add(new byte[1024*1024]);
            }
        }finally {
            long t2=System.currentTimeMillis();
//System.out.println("oom:"+(t2-t1));
        }
    }
}
运行时可设置虚拟机参数
-Xmx50m -Xms10m -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=e:/a.dump
说明:如上代码在运行了一段时间以后会出现堆内存溢出 (OutOfMemoryError), 可通过调整堆内存大小,延迟内存溢出的时间。

代码演示:元数据内存溢出(JDK8)

当在有限的元数据内存区不断的加载新的类时会导致元数据区空间不足从而出 现内存溢出现象,例如:
public class MetaSpaceTest {

    public static void main(String[] args) {
        int i = 0;
        try {
            for (i = 0; i < 100000; i++) {
                new CglibBean(new HashMap<>());
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            System.out.println("total create count:" + i);
        }
    }

    public static class CglibBean {

        public CglibBean(Object object) {
            Enhancer enhancer = new Enhancer();
            enhancer.setUseCache(false);
            enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> obj);
            enhancer.setSuperclass(object.getClass());
            enhancer.create();
        }
    }
}

上述代码通过Cglib生成大量的HashMap代理,下面我们在运行这段代码的时候指定下列参数

-XX:MaxMetaspaceSize=100M -XX:+PrintGCDetails

当我们程序循环至3660次,也就是说我们大约在生成了约3660个代理类以后元数据区发生了内存溢出,下面将MaxMetaspaceSize改为50M执行,

 从上图可以看出当我们生成了1710个代理类以后元数据区发生了内存溢出,可见一个元数据区的大小决定了Java虚拟机可以装载的类的多少。

3.2. JVM 工具应用分析篇

3.2.1. 命令行工具篇

1. Jps [options] [hostid] (hostid ip 或域名地址)
jps 是用于查看有权访问的 hotspot 虚拟机的进程,当未指定 hostid 时,默认 查看本机 jvm 进程。
-q 不输出类名、 Jar 包 名和传入 main 方法的参数
-m 输出传入 main 方法的参数
-l 输出 main 类或 Jar 的全限名
-v 输出传入 JVM 的参数
 例如:
代码示例
执行:
1)Jps -l 输出应用程序主类完整 package 名称或 jar 完整名称 .
2)Jps -v 列出 jvm 参数
2. jmap -heap pid
用于打印指定 Java 进程的对象内存映射或堆内的细节。
代码案例
public class TestCommand {
    public static void main(String[] args) {
        while (true) {
            byte[] b1 = new byte[1024 * 1024];
        }
    }

}
例如获取如上代码的进程 id 之后,执行 jmap -heap 24966 可检测堆的配置 信息,还可以借助 jmap -histo:live 1963 快速定位内存泄露。
其中:
1) MaxHeapFreeRatio:  最大空闲堆内存比例
最大空闲对内存比例, GC 后如果发现空闲堆内存大于整个预估堆内存的 N%(百分比 ) JVM 则会收缩堆内存,但不能小于 -Xms 指定的最小堆的限制。
2) MinHeapFreeRatio: 最小空闲堆内存比例
GC 后如果发现空闲堆内存小于整个预估堆内存的 N%( 百分比 ), JVM 会增大 堆内存,但不能超过 -Xmx 指定的最大堆内存限制。
3) MaxHeapSize: -Xmx, 堆内存大小的上限
4) InitialHeapSize: -Xms, 堆内存大小的初始值
5) NewSize: 新生代预估堆内存占用的默认值
6) MaxNewSize: 新生代占整个堆内存的最大值
7) OldSize: 老年代的默认大小 ,
8) NewRatio:
老年代对比新生代的空间大小 , 比如 2 代表老年代空间是新生代的两倍大小 .
9) SurvivorRatio:
Eden/Survivor 的值 . 例如 8 表示 Survivor:Eden=1:8, 因为 survivor   2 , 所以 新生代  Eden 的占比为 8/10 
10)MetaspaceSize:
分配给类元数据空间的初始大小 (Oracle 逻辑存储上的初始高水位,the initial high-water-mark ). 此值为估计值 . MetaspaceSize 设置得过大,会延长垃圾回收时间 . 垃圾回收过后 , 引起下一次垃圾回收的类元数据空间的 大小可能会变大
11)MaxMetaspaceSize:
是分配给类元数据空间的最大值 , 超过此值就会触发 Full GC. 此值仅受限系统内存的大小 , JVM 会动态地改变此值
12)CompressedClassSpaceSize:
类指针压缩空间大小 , 默认为 1G.
13)G1HeapRegionSize:
G1 区块的大小 , 取值为 1M 32M. 其取值是要根据最小 Heap 大小划分出 2048 个区块 .
说明 :jmap 在系统调优时通常会结合 jhat 来分析 jmap 生成的 dump 文件。
3. jstack 用于生成 java 虚拟机当前时刻的线程快照
生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
示例代码:
class SyncTask02 implements Runnable {
    private List<Integer> from;
    private List<Integer> to;
    private Integer target;

    public SyncTask02(List<Integer> from, List<Integer> to, Integer target) {
        this.from = from;
        this.to = to;
        this.target = target;
    }

    @Override
    public void run() {
        moveListItem(from, to, target);
        
    }

    private static void moveListItem(List<Integer> from,
                                     List<Integer> to, Integer item) {
        log("attempting lock for list", from);
        synchronized (from) {
            log("lock acquired for list", from);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log("attempting lock for list ", to);
            synchronized (to) {
                log("lock acquired for list", to);
                if (from.remove(item)) {
                    to.add(item);
                }
                log("moved item to list ", to);
            }
        }
    }

    private static void log(String msg, Object target) {
        System.out.println(Thread.currentThread().getName() +
                ": " + msg + " " +
                System.identityHashCode(target));
    }
}

public class TestDeadLock02 {
    public static void main(String[] args) {
        List<Integer> list1 = new ArrayList<>(Arrays.asList(2, 4, 6, 8,
                10));
        List<Integer> list2 = new ArrayList<>(Arrays.asList(1, 3, 7, 9,
                11));

        Thread thread1 = new Thread(new SyncTask02(list1, list2, 2));
        Thread thread2 = new Thread(new SyncTask02(list2, list1, 9));
        thread1.start();
        thread2.start();
    }
} 
例如 执行 jstack -l 22345 ,检测到死锁问题:
3.2.2. GUI 工具篇:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1599789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全球顶级的低代码开发平台,你知道几个?

什么是低代码开发平台? 低码开发平台是一个应用程序,提供图形用户界面编程,从而以非常快的速度开发代码,减少了传统的编程工作。 这些工具有助于快速开发代码,最大限度地减少手工编码的努力。这些平台不仅有助于编码,而且还能快速安装和部署。 低码开发工具的好处 低代码平…

2024Spring> HNU-计算机系统-实验3-Bomblab-导引/答疑

前言 BombLab一定要花时间完成哦&#xff0c;对于期末卷面的提升和计算机系统的理解都非常重要。 导引 ①文件目录概览 助教下发一个文件包&#xff0c;打开之后是这样的几个文件。 这几个文件解释如下 bomb&#xff1a;可执行文件&#xff0c;无法打开&#xff0c;我们主要…

拥抱企业消费新纪元,胜意科技2024代理人大会圆满落幕

因信赖相聚&#xff0c;为共赢而来。近日&#xff0c;由胜意科技主办的“做好生意&#xff0c;拥抱胜意——2024代理人大会”在武汉成功召开&#xff0c;吸引了全国各地百余家TMC生态合作伙伴齐聚一堂&#xff0c;共同探讨数字化浪潮下的差旅管理实践&#xff0c;激发增长新智慧…

突破编程_前端_SVG(使用 svg-pan-zoom 库进行平移与缩放)

1 svg-pan-zoom 概述 svg-pan-zoom 是一个轻量级、高性能且易于使用的 JavaScript 库&#xff0c;专为增强 SVG 图像的浏览体验而设计。它提供了平移和缩放功能&#xff0c;使用户能够无缝探索大型或复杂的 SVG 图形。这个库允许用户对SVG图像进行交互操作&#xff0c;包括缩放…

Transformer的Decoder的输入输出都是什么

目录 1 疑问&#xff1a;Transformer的Decoder的输入输出都是什么 2 推理时Transformer的Decoder的输入输出 2.1 推理过程中的Decoder输入输出 2.2 整体右移一位 3 训练时Decoder的输入 参考文献&#xff1a; 1 疑问&#xff1a;Transformer的Decoder的输入输出都是什么 …

【Redis 神秘大陆】009 案例实践进阶

九、案例实践&进阶方案 9.1 本地缓存组件选型 使用缓存组件时需要重点关注集群方式、集群、缓存命中率。 需要关注集群组建方式、缓存统计&#xff1b;还需要考虑缓存开发语言对缓存的影响&#xff0c;如对于JAVA开发的缓存需要考虑GC的影响&#xff1b;最后还要特别关注…

CubelMX点灯

工程配置 开发板led引脚图 工程io配置 配置PB5 为输出 配置 PE5 为输出 时钟配置 写测试代码 配置工程&#xff0c;下载运行。 参考链接 STM32入门教程-1.点灯_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1dC41147eL/?spm_id_from333.788&vd_sourcee821a225c7b…

机器人交互新纪元:讯飞星火大模型引领升级浪潮

放眼全球&#xff0c;大模型浪潮从前沿话题到规模落地&#xff0c;传统计划和商业模式正在“重构”。依托大模型的持续迭代与快速升级&#xff0c;从文本生成、图像生成乃至视频生成&#xff0c;AI不断改变工作本质&#xff0c;为产业发展注入“超能量”。 当众多行业还在探索大…

NL2SQL进阶系列(5):论文解读业界前沿方案(DIN-SQL、C3-SQL、DAIL-SQL、SQL-PaLM)、新一代数据集BIRD-SQL解读

NL2SQL进阶系列(5)&#xff1a;论文解读业界前沿方案&#xff08;DIN-SQL、C3-SQL、DAIL-SQL&#xff09;、新一代数据集BIRD-SQL解读 NL2SQL基础系列(1)&#xff1a;业界顶尖排行榜、权威测评数据集及LLM大模型&#xff08;Spider vs BIRD&#xff09;全面对比优劣分析[Text2…

随笔-做好卖麻辣烫的准备

前两天突然接到宝哥的微信&#xff0c; 宝哥&#xff1a;有啥项目没有&#xff1f; 我&#xff1a;&#xff1f;啥项目&#xff1f; 宝哥&#xff1a;那个卖奶茶的。 我&#xff1a;什么情况&#xff0c;你要去卖奶茶啊。 宝哥&#xff1a;有这个打算&#xff0c;年前被裁…

CodeForce[1500-2000]——1946D Birthday Gift

codeforce刷题日记 题目大意:一道位运算有关的题&#xff0c;题目大意是给一个长度为n的整形数组&#xff0c;要求将其分成连续的k段&#xff0c;让每段的元素异或后的结果进行或运算&#xff0c;要让这个值<x&#xff0c;求k的最大值。 问题难点在分成k段的依据是什么&…

LeetCode 每日一题 Day 123-136

1379. 找出克隆二叉树中的相同节点 给你两棵二叉树&#xff0c;原始树 original 和克隆树 cloned&#xff0c;以及一个位于原始树 original 中的目标节点 target。 其中&#xff0c;克隆树 cloned 是原始树 original 的一个 副本 。 请找出在树 cloned 中&#xff0c;与 tar…

【k8s】:深入理解 Kubernetes 中的污点(Taints)与容忍度(Tolerations)

【k8s】&#xff1a;深入理解 Kubernetes 中的污点&#xff08;Taints&#xff09;与容忍度&#xff08;Tolerations&#xff09; 1、污点&#xff08;Taints&#xff09;2、容忍度&#xff08;Tolerations&#xff09;3、示例演示-测试污点的具体应用场景3.1 给节点打污点&…

【C++】类和对象③(类的默认成员函数:拷贝构造函数 | 赋值运算符重载)

&#x1f525;个人主页&#xff1a;Forcible Bug Maker &#x1f525;专栏&#xff1a;C 目录 前言 拷贝构造函数 概念 拷贝构造函数的特性及用法 赋值运算符重载 运算符重载 赋值运算符重载 结语 前言 本篇主要内容&#xff1a;类的6个默认成员函数中的拷贝构造函数…

算法练习第17天|104.二叉树的最大深度 、559.N叉树的最大深度

104.二叉树的最大深度 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/maximum-depth-of-binary-tree/description/ 什么是二叉树的深度和高度&#xff1f; 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。最大深度…

03_信号和槽

信号和槽 系统的信号和槽自定义信号和槽Lambda表达式 系统的信号和槽 下面我们完成一个小功能&#xff0c;上面我们已经学习了按钮的创建&#xff0c;但是还没有体现出按钮的功能&#xff0c;按钮最大的功能也就是点击后触发一些事情&#xff0c;比如我们点击按钮&#xff0c;…

链表里面头节点存在的目的

头节点存在的目的&#xff1a; 在单链表的使用中&#xff0c;头结点&#xff08;Header Node&#xff09;是一个常用的概念&#xff0c;特别是在进行链表操作时。头结点不是数据域中实际存储的数据节点&#xff0c;而是作为链表操作的辅助节点&#xff0c;它包含对第一个实际数…

二路归并排序的算法设计和复杂度分析(C语言)

目录 实验内容&#xff1a; 实验过程&#xff1a; 1.算法设计 2.程序清单 3.运行结果 4.算法复杂度分析 实验内容&#xff1a; 二路归并排序的算法设计和复杂度分析。 实验过程&#xff1a; 1.算法设计 二路归并排序算法&#xff0c;分为两个阶段&#xff0c;首先对待排…

HADOOP大数据处理技术7-JavaSe

一粒尘埃 在空气中凝结 最后生成磅礴的风 ​ 生活有时会像一场暴风雨&#xff0c;狂风骤雨让人无法呼吸&#xff0c;但即使如此&#xff0c;也请记住&#xff0c;每一次风雨过后都会是一轮明媚的阳光。在黑暗中寻找光明&#xff0c;在困境中寻找希望&#xff0c;因为最终胜利属…

T细胞耗竭

目录 T Cell Exhaustion T 细胞衰竭路径上的细胞和分子路标 研究起源 介绍 T 细胞耗竭的发生路径 耗尽的T细胞亚群的解剖分离和迁移 持续TCR刺激的收益递减 通过共调节受体进行发育微调 细胞因子介导的耗尽T细胞亚群的特异性 T细胞耗竭和表观遗传 T Cell Exhaustion…