JVM_内存区域与内存溢出异常

news2024/9/30 3:34:48

文章目录

  • 一、运行时数据区域
    • 1、程序计数器
    • 2、Java虚拟机栈
    • 3、本地方法栈
    • 4、Java堆
    • 5、方法区
    • 6、运行时常量池
    • 7、直接内存
    • 二、HotSpot虚拟机对象
    • 1、对象的创建
    • 2、对象的内存布局
    • 3、对象的访问定位
  • 三、OutOfMemoryError和StackOverflowError异常
    • 1、Java堆溢出(最常见)
    • 2、虚拟机栈和本地方法栈溢出
      • 1、通过设置-Xss参数减少栈内存容量使栈溢出
      • 2、定义大量本地变量,增大此方法帧中本地变量表的长度使栈溢出
    • 3、方法区和运行时常量池溢出
      • 3.1 运行时常量池溢出
      • 3.2 方法区溢出
    • 4、本机直接内存溢出
  • 总结

一、运行时数据区域

运行时数据区域有1、Method Area方法区 2、VM Stack虚拟机栈 3、Native Method Stack本地方法栈 4、Heap堆 5、Program Counter Register程序计数器。
Method Area方法区、Heap堆是由所有线程共享的数据区。其余3个是线程隔离的数据区。

1、程序计数器

  1. Program Counter Register程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在Java虚拟机概念模型中,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
    即Program Counter Register是一个“数值”,字节码解释器可以改变它,线程需要使用它才能继续向下执行。
  2. Java虚拟机的多线程是通过线程轮流切换,分配处理器执行时间的方式来实现的。为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,这类内存区域为“线程私有”的内存。
  3. 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;
    如果正在执行的是本地方法,这个计数器值为空(Undefined)。

2、Java虚拟机栈

Java虚拟机栈也是线程私有的,它的生命周期和线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行时,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
虚拟机的局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(byte、short、int、long、boolean、char、float、double)、对象引用(reference类型,它并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。
这些数据类型在局部变量表中的存储空间以局部变量槽(slot)来表示,其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占一个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要的栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
内存区域规定的两类异常状况:1、线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常。2、Java虚拟机栈容量可以动态扩展,当栈扩展时,无法申请到足够的内存会抛出OutOfMemoryError异常。

3、本地方法栈

本地方法栈和虚拟机栈的区别只是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的本地方法服务。
本地方法栈也会抛出StackOverFlowError和OutOfMemoryError异常。
HotSpot虚拟机直接就把本地方法栈和虚拟机栈合二为一。

4、Java堆

对于Java应用程序而言,Java堆(Java Heap)是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java中几乎所有对象实例都在这里分配内存。
Java堆是垃圾收集器管理的内存区域,也称作GC堆。
Java堆既可以实现成固定大小,也可以是可扩展的,当前主流的Java虚拟机都是按照可扩展来实现的(通过参数-Xmx和-Xms设定)。如果Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError异常。

5、方法区

方法区也是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
JDK8后,方法区将在本地内存中实现的元空间来代替永久代。

6、运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。
Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
并非预置入Class文件后常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,这种特性被利用得比较多的就是String类的intern()方法。

7、直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,但是也被频繁使用,也可以导致OutOfMemoryError异常。
JDK1.4中加入NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方法,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

二、HotSpot虚拟机对象

1、对象的创建

当虚拟机遇到一条字节码new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则必须先执行相应的类加载过程。
虚拟机为新生对象分配内存,有指针碰撞(Bump The Pointer)和空闲列表(Free List)两种方式。
1)指针碰撞,当Java堆中内存是绝对规整的,所有被使用过的内存都被放在一边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,分配内存时就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离。
2)空闲列表,当Java堆中内存不是规整的,已使用的内存和空闲内存相互交错在一起,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候回从列表中找到一块足够大的空间划分给对象实例,并更新表上的记录。
这两种划分可用空间,当遇到并发情况时,不是线程安全的。
需要在划分可用空间的基础上,解决并发,有对分配内存空间的操作进行同步处理和本地线程分配缓冲两种解决方案。
1)对分配内存空间的操作进行同步处理,也就是虚拟机采用的CAS配上失败重试的方式来保证更新操作的原子性。
2)本地线程分配缓冲,即每个线程在Java堆中预先分配一小块内存。当本地缓冲区用完了,分配新的缓冲区时才需要同步锁定。可以通过-XX:+/-UseTLAB参数来设定。
此时从虚拟机的视角,一个新的对象已经产生;程序中遇到new之后会继续执行init()方法,此时一个真正可用的对象才算完全被构造出来。

2、对象的内存布局

对象在堆内存中的存储布局可以划分为3个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

1)对象头部分包括用于存储对象自身的运行时数据和类型指针这两类信息。

  1. 运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,称为“Mark Word”。
  2. 类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例。

2)实例数据是对象真正存储的有效信息,即在程序代码里面所定义的各种类型的字段内容,无论是从父类中继承下来的,还是在子类中定义的字段都必须记录起来。
3)对齐填充,仅仅起着占位符的作用。任何对象的大小必须是8个字节的正整数倍,如果对象实例数据部分没有对齐,就需要对齐填充来补全。

3、对象的访问定位

Java程序会通过栈上的reference数据来操作堆上的具体对象。
主流的访问方式主要有使用句柄和直接指针两种:

  1. 使用句柄访问的话,Java堆中将可能会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据与类型数据各自具体的地址信息
  2. 使用直接指针访问的话,Java堆中对象的内存布局就必须考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址,只是访问对象本身的话,就不需要像句柄访问那样多一次间接访问的开销。

这两种访问方式各有优势,使用句柄来访问的最大好处就是reference中存储的是稳定句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要被修改。
使用直接指针来访问最大的好处就是速度更快,它节省了一次指针定位的时间开销,由于对象访问在Java中非常频繁,节省的时间开销也是极为可观的。
即句柄访问是属于间接访问对象实例数据和对象类型数据的;而直接指针访问是属于直接访问对象实例数据和间接访问对象类型数据的。
HotSpot虚拟机使用直接指针访问的。

三、OutOfMemoryError和StackOverflowError异常

1、Java堆溢出(最常见)

限制堆大小为20M,不可扩展(将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展),再通过设置参数 -XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时,Dump出当前的内存堆转储快照以便事后分析。

  1. 创建包outofmemoryerror,再创建类HeapOOM

    package outofmemoryerror;
    
    import java.util.ArrayList;
    
    public class HeapOOM {
        static class OOMObject
        {
    
        }
    
        public static void main(String[] args) {
            ArrayList<OOMObject> oomObjects = new ArrayList<>();
            while(true) {
                oomObjects.add(new OOMObject());
            }
        }
    }
    
    

    因为创建的对象实例会存放在堆中,一直创建可以让堆内存溢出。

  2. IDEA中,先通过编辑参数配置
    在这里插入图片描述

  3. 再修改选项
    在这里插入图片描述

  4. 最后添加VM选项即可
    在这里插入图片描述

  5. 在VM Arguments框中输入:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError,再运行即可。

2、虚拟机栈和本地方法栈溢出

HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,因此对于HotSpot来说,-Xoss参数(设置本地方法栈大小)虽然存在,但实际上是没有效果的,栈容量只能由-Xss参数来设定。
1)线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
2)虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够的内存时,将抛出OutOfMemoryError异常。但是HotSpot虚拟机时不支持栈扩展的。
所以在运行时,线程只会因为栈容量无法容纳新的栈帧而导致StackOverflowError异常。

1、通过设置-Xss参数减少栈内存容量使栈溢出

  1. 创建包stackoverflowerror,再创建类JavaVMStackSOF

    package stackoverflowerror;
    
    public class JavaVMStackSOF {
        private int stackLength = 1;
        public void stackLeak()
        {
            stackLength++;
            stackLeak();
        }
    
        public static void main(String[] args) {
            JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF();
            try{
                javaVMStackSOF.stackLeak();
            }catch (Throwable e){
                System.out.println("stackLength: "+javaVMStackSOF.stackLength);
                throw e;
            }
        }
    }
    
    

    因为JVM运行时,关于栈只能抛出StackOverflowError异常,将stackLeak()方法调用后,它会进行无限递归调用,直到栈溢出。

  2. 将VM Arguments参数设置为-Xss180k,因为64位windows下的JDK11创建JVM时,栈的最小内存为180k。然后运行即可。
    在这里插入图片描述
    设置栈内存为最小内存容量,是因为可以在栈最小的深度时输出异常。从而减少输出栈深度。

2、定义大量本地变量,增大此方法帧中本地变量表的长度使栈溢出

  1. 创建包stackoverflowerror,创建类JavaVMStackSOF2

    package stackoverflowerror;
    
    public class JavaVMStackSOF2 {
        private static int stackLength = 1;
        public static void stack()
        {
            long user0,user1,user2,user3,user4,user5,user6,user7,user8,user9,
                 user10,user11,user12,user13,user14,user15,user16,user17,user18,user19,
                 user20,user21,user22,user23,user24,user25,user26,user27,user28,user29,
                 user30, user31,user32,user33,user34,user35,user36,user37,user38,user39,
                 user40,user41,user42,user43,user44,user45,user46,user47,user48,user49,user50;
            stackLength++;
            stack();
            user0=user1=user2=user3=user4=user5=user6=user7=user8=user9=
                    user10=user11=user12=user13=user14=user15=user16=user17=user18=user19=
                    user20=user21=user22=user23=user24=user25=user26=user27=user28=user29=
                    user30=user31=user32=user33=user34=user35=user36=user37=user38=user39=
                    user40=user41=user42=user43=user44=user45=user46=user47=user48=user49=user50=0;
    
        }
    
        public static void main(String[] args) {
            JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF();
            try{
                javaVMStackSOF.stack();
            }catch (Throwable e){
                System.out.println("stackLength: "+javaVMStackSOF.stackLength);
                throw e;
            }
        }
    }
    
    

    跟前面方法一样,并且多了很多本地变量,但是不设置栈的内存容量,直接运行即可。此时会因为本地变量太多,并且递归,使得栈溢出。

3、方法区和运行时常量池溢出

运行时常量池是方法区的一部分。
自JDK7开始,原本存放在永久代的字符串常量池被移至Java堆中。
String::intern()是一个本地方法,作用是如果常量池中已经包含一个等于此String对象的字符串,则返回该String对象的引用;否则则将其添加到常量池中,再返回该String对象的引用。

3.1 运行时常量池溢出

  1. 创建包outofmemoryerror,再创建类RuntimeConstantPoolOOM

    package outofmemoryerror;
    
    import java.util.HashSet;
    import java.util.Set;
    
    public class RuntimeConstantPoolOOM {
        public static void main(String[] args) {
            //使用Set保持着常量池引用,避免Full GC回收常量池行为
            Set<String> set = new HashSet<>();
            //在short范围内足以让6MB的PermSize产生OutOfMemoryError了
            short i = 0;
            while(true)
            {
                set.add(String.valueOf(i++).intern());
            }
        }
    }
    
    
  2. 设置VM Arguments为-Xmx6M,即Java堆最大内存为6M
    在这里插入图片描述
    此时由于反复调用intern()方法(将其添加到常量池中),又因为运行时常量池在Java堆中,后面又设置Java堆的大小为6m,从而出现OutOfMemoryError异常。

3.2 方法区溢出

方法区的主要职责是用于存放类型的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。
JDK8后,元空间代替了永久代。并且HotSpot虚拟机提供了一些参数作为元空间的防御措施:
1)-XX:MaxMetaspaceSize:设置元空间最大值,默认值为-1,即不限制,或者说只受于本地内存大小。
2)-XX:MetaspaceSize:指定元空间的初始空间大小,以字节为单位,达到该值就会出发垃圾手机进行类型卸载,同时收集器会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过-XX:MaxMetaspaceSize的情况下,适当提高该值。
3)-XX:MinMetaspaceFreeRatio:作用是在垃圾收集后控制最小的元空间剩余容量的百分比,可减少因为元空间不足导致的垃圾收集的频率。

4、本机直接内存溢出

直接内存(Direct Memory)的容量大小可通过-XX:MaxDirectMemorySize参数指定,不指定则默认跟Java堆最大值一致。

总结

  1. 运行时数据区域有1、Method Area方法区 2、VM Stack虚拟机栈 3、Native Method Stack本地方法栈 4、Heap堆 5、Program Counter Register程序计数器。
    1)程序计数器是线程所执行的字节码的行号指示器,即Program Counter Register是一个“数值”,字节码解释器可以改变它的数值,从而实现选取下一条指令。线程需要使用它才能继续向下执行。
    2)Java虚拟机栈描述的是Java方法执行的内存模型。
    3)本地方法栈是为虚拟机使用到的本地方法服务,也Java虚拟机栈相似。
    4)Java堆这内存区域的唯一目的就是存放对象实例,是被所有线程共享的一块内存区域,主流虚拟机一般是将Java堆按照可扩展来实现的。
    5)方法区用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
    6)运行时常量池,即在类加载后,将Class文件的常量池表存放到方法区的运行时常量池中。
    7)直接内存,并不是虚拟机运行时数据区的一部分,但是也被频繁使用。
    OutOfMemoryError异常,在虚拟机栈、本地方法栈、Java堆、方法区、运行时常量池、直接内存中都有可能抛出。
    StackOverFlowErrory异常,在虚拟机栈和本地方法栈中可能抛出。
  2. 当虚拟机遇到New指令时,会进行检查这个符号引用。没有被加载、初始化等操作,则必须先执行相应的类加载过程。
    虚拟机为新生对象分配内存,有指针碰撞(Bump The Pointer)和空闲列表(Free List)两种方式划分可用空间。
    这两种划分可用空间,当遇到并发情况时,不是线程安全的。
    需要在划分可用空间的基础上,解决并发,有对分配内存空间的操作进行同步处理和本地线程分配缓冲两种解决方案。此时从虚拟机的视角,一个新的对象已经产生;程序中遇到new之后会继续执行init()方法,此时一个真正可用的对象才算完全被构造出来。
    对象在堆内存中的存储布局可以划分为对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)3个部分。对象头存的是对象运行时数据,而实例数据存的是对象本身,对齐填充则是当对象头+实例数据的大小不是8个字节的正整数倍时,进行一个填充。
    对象的访问定位,Java程序会通过栈上的reference数据来操作堆上的具体对象,主要有使用句柄和直接指针两种。
  3. Java堆溢出异常是实际应用中最常见的内存溢出异常。-Xms与-Xmx之间的差值为可扩展的空间。
    线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。可以通过-Xss参数减少栈容量或者通过定义大量本地变量,从而更快的使栈溢出。

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

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

相关文章

闭包可能导致的内存泄漏

什么是闭包 闭包是函数可以保留和访问其外部变量&#xff0c;比如 let a 1 let b function() {console.log(a) }这里变量b指向的函数可以访问外面的变量&#xff0c;你会说这不是废话吗&#xff1f;函数都可以访问外部变量呀 那再看一个例子 function f() {let value 123…

人人都能看懂的Spring源码解析,配置解析与BeanDefinition加载注册

人人都能看懂的Spring源码解析&#xff0c;扫描加载BeanDefinition的过程原理解析什么是BeanDefinition&#xff1f;两种配置方式扫描并读取配置信息&#xff0c;解析成BeanDefinition保存BeanDefinition源码走读xml配置方式整体流程示例代码BeanDefinition加载解析的入口创建X…

机器学习基础

一、基本概念 1 学习的概念 1975年图灵奖获得者、1978年诺贝尔经济学奖获得者、著名学者赫伯特.西蒙 (Herbert Simon) 曾下过一个定义: 如果一个系统&#xff0c;能够通过执行某个过程&#xff0c;就此改进了它的性能&#xff0c;那么这个过程就是学习.由此可看出&#xff0c;…

思科基础组面试(部分)

面了三轮&#xff0c;前面两轮因为录的视频坏了&#xff0c;很多问题忘了。 Round 1 Q:举例说明为什么hashmap线程不安全 A1: JDK1.8 HashMap线程不安全体现在&#xff1a;数据覆盖: 其中第六行代码是判断是否出现hash碰撞&#xff0c;假设两个线程A、B都在进行put操作&#…

软件测试未来发展趋势怎么样

未来&#xff0c;互联网技术是很多企业能够活下去的关键点。互联网技术成为新的基建&#xff0c;互联网“基建”化就决定了软件测试行业的缺口会一直扩大。 并且&#xff0c;软件测试岗位&#xff0c;已不仅局限于互联网企业&#xff0c;现已逐步深入到实体产业&#xff0c;金…

【安全等保】安全等保二级和三级哪个高?哪个费用更高?

等保政策已经严格落地执行了&#xff0c;各大企业纷纷接到了过等保的通知&#xff0c;但有的估计是第一次听到等保&#xff0c;对于等保相关政策都是非常蒙圈的。这不不少企业相关负责人在问&#xff0c;安全等保二级和三级哪个高&#xff1f;哪个费用更高&#xff1f;这里我们…

分布式文件系统使用——MinIO

分布式文件系统使用——MinIO 1 分布式文件系统 1.1 概念 常见的文件系统&#xff1a;FAT16/FAT32、NTFS、HFS、UFS、APFS、XFS、Ext4等 。 现在有个问题&#xff0c;一此短视频平台拥有大量的视频、图片&#xff0c;这些视频文件、图片文件该如何存储呢&#xff1f;如何存储…

04- 根据Xgboost集成算法预测还贷能力 (项目四)

筛选最佳参数: # 对于max_depth和min_child_weight查找最好的参数 param_grid { max_depth:range(3,10,2),min_child_weight:range(1,6,2)}model XGBClassifier(learning_rate 0.1,n_estimators100,max_depth5,use_label_encoderFalse,min_child_weight1,gamma0,subsample0…

状态管理VueX

哈喽~大家好&#xff0c;这篇来看看状态管理VueX。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【专栏】 &#x1f949;与这篇相关的文章&#xff1a; SpringCloud Sentinel 使用SpringClou…

java整数转罗马数字

罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即为两个并列的 1。12 写做 XII &#xff0c;即为…

低版本jQuery导致XSS Nuclei FUZZ POC

目录 1.前言 2. Nuclei FUZZ jQuery XSS POC 3.漏洞验证 4.修复建议 1.前言 我记得以前用那些漏扫工具时时常会报一个低版本jQuery的安全问题,当时还不会验证。直到有一天,它托梦给我。我悟了。低版本jQuery导致XSS POC文件文末获取。

java.io.IOException: Could not find resource com/itheima/mapper/UserMapper.xml

问题&#xff1a;Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/itheima/mapper/UserMapper.xml问题描述&#xff1a;找不到UserMapper解决方案&#xff1a;这是我原来的路径这是我改后的路径&#xff08;很重要&#xff…

羊了个羊游戏开发教程2:随机生成卡牌

本文首发于微信公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。上一节教程里我们实现了游戏中最难的地方——堆叠牌的拾取&#xff0c;这节教程我们来继续学…

关于CountDownLatch

关于CountDownLatchCountDownLatch 是什么CountDownLatch 如何工作CountDownLatch API使用示例与 Join 的区别CountDownLatch 是什么 CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如&#xff0c;应用程序的主线程希望在负责启动框架服务的线程已…

强化学习基础

强化学习的三种方法 基于价值&#xff08;value-based&#xff09; 基于策略&#xff08;policy-based&#xff09; 基于模型&#xff08;model-based&#xff09; 一 基于价值的方法 基于价值 (Value-Based)这种方法&#xff0c;目标是优化价值函数V(s)。 价值函数会告诉我们…

LeetCode 1669. 合并两个链表(C++)

思路&#xff1a; 该题思路很简单&#xff0c;对于单向链表&#xff0c;先遍历到指定的右边界的位置b1&#xff0c;做好标记供连接&#xff1b; 然后对于a-1位置的结点&#xff0c;连接list2&#xff0c;并最后连接后半段的list1 1.题目如下&#xff1a; 给你两个链表 list1 …

ATX agent+UIautomation2 自动化测试介绍

目前ATXUIautomator2 处于自动化界的浪口风尖&#xff0c;现在有幸终于有时间对ATX进行了粗浅的了解 为什么要用ATX ATXUIautomator2的优势&#xff1a; 1.速度吊打appnium&#xff0c;群里面的人这样说的 运行速度快&#xff0c;比Appium运行速度快了好多。&#xff08;用…

分布式架构

目录 一、前言 二、分布式架构的发展历史 三、分布式架构发展的里程碑 四、分布式系统的意义 五、分布式架构的常见概念 六、分布式领域中冯诺依曼模型的变化 七、分布式系统的难点 八、总结 一、前言 ​  我们都知道&#xff0c;当今无论在BAT这样的大公司&#xff…

Install Linux on Windows with WSL2 (使用 WSL2 在 Windows 上安装 Linux)

Install Linux on Windows with WSL2 (使用 WSL2 在 Windows 上安装 Linux)https://learn.microsoft.com/en-us/windows/wsl/ 在 Windows 上运行 Linux - 在 Windows 11 上运行 Ubuntu 20.04 LTS Developers can access the power of both Windows and Linux at the same tim…

实验十三、阻容耦合共射放大电路的频率响应

一、题目 利用 Multism 从以下几个方面研究图1所示的阻容耦合共射放大电路的频率响应。图1阻容耦合共射放大电路图1\,\,阻容耦合共射放大电路图1阻容耦合共射放大电路&#xff08;1&#xff09;设 C1C210μFC_1C_210\,\textrm{μF}C1​C2​10μF&#xff0c;分别测试它们所确定…