【jvm系列-09】垃圾回收底层原理和算法以及JProfiler的基本使用

JVM系列整体栏目


内容链接地址
【一】初识虚拟机与java虚拟机https://blog.csdn.net/zhenghuishengq/article/details/129544460
【二】jvm的类加载子系统以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963
【三】运行时私有区域之虚拟机栈、程序计数器、本地方法栈https://blog.csdn.net/zhenghuishengq/article/details/129684076
【四】运行时数据区共享区域之堆、逃逸分析https://blog.csdn.net/zhenghuishengq/article/details/129796509
【五】运行时数据区共享区域之方法区、常量池https://blog.csdn.net/zhenghuishengq/article/details/129958466
【六】对象实例化、内存布局和访问定位https://blog.csdn.net/zhenghuishengq/article/details/130057210
【七】执行引擎,解释器、JIT即时编译器https://blog.csdn.net/zhenghuishengq/article/details/130088553
【八】精通String字符串底层机制https://blog.csdn.net/zhenghuishengq/article/details/130154453
【九】垃圾回收底层原理和算法以及JProfiler的基本使用https://blog.csdn.net/zhenghuishengq/article/details/130261481

垃圾回收篇底层原理及相关算法

  • 一,垃圾回收篇底层原理
    • 1,垃圾回收概述
      • 1.1,什么是垃圾
      • 1.2,为什么需要gc
      • 1.3,java垃圾回收机制
    • 2,垃圾回收算法
      • 2.1,垃圾标记阶段
        • 2.1.1,引用计数算法
        • 2.2.2,可达性分析算法
    • 3,JProfiler查看GC Root
    • 4,垃圾回收相关算法
      • 4.1,标记清除算法
      • 4.2,复制算法
      • 4.3,标记整理算法
      • 4.4,三种算法总结
    • 5,垃圾回收相关概念
      • 5.1,System.gc() 的理解
      • 5.2,内存溢出和内存泄漏
        • 5.2.1,内存溢出(OOM)
        • 5.2.2,内存泄漏
      • 5.3,Stop The World
      • 5.4,引用

一,垃圾回收篇底层原理

1,垃圾回收概述

1.1,什么是垃圾

垃圾收集,并不是Java语言的产物,早在1960年,第一门使用内存动态分配和垃圾收集技术的Lisp语言诞生。垃圾回收机制也是Java的招牌能力,极大地提高了开发效率。因此在面对垃圾回收时,需要解决三个主要的问题:哪些内存需要回收、什么时候回收、如何回收?

在这里插入图片描述

垃圾:指的是在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。如创建了某个对象,引用该对象的变量是存储在虚拟机栈的栈帧中,随着入栈出栈该栈帧被销毁,那么栈帧中引用该对象的局部变量变量也被销毁,此时没有任何变量引用着刚刚创建的对象,那么该对象就会变成垃圾,等待回收。

1.2,为什么需要gc

首先如果垃圾不回收,内存很容易被消耗完,在面对一个大系统的时候,没有GC就很难保证应用程序正常运行。

如果不及时的对内存中的垃圾进行回收, 那么这些对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用,甚至会出现内存溢出的情况。

1.3,java垃圾回收机制

java内部通过自动内存管理的方式,无需开发人员手动参与内存的分配和回收,这样可以降低内存泄漏和内存溢出的问题,从而省去繁重的内存管理,可以更加专注的进行业务开发。

然而自动内存管理就如同一个黑匣子,如果过度依赖自动化,那么就会弱化开发人员在程序出现内存溢出时定位问题和解决问题的能力。因此当需要排查各种内存溢出、内存泄漏等问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,就需要对这个垃圾回收进行必要的监控和调节

在进行垃圾回收时,主要针对的是Java堆的这个区域。从次数上来说,频繁的收集Young区,较少的收集Old区域,基本不动方法区(永久代或者元空间)

2,垃圾回收算法

在这垃圾回收的算法中,主要是做了两件事情:一件是找出垃圾,另一件是清除垃圾

2.1,垃圾标记阶段

垃圾标记阶段主要就是找出垃圾,用于判断对象是否存活。堆中几乎所有的对象都存储在堆中,在GC执行垃圾回收之前,需要先区分哪些是存活的对象,哪些是已经死亡的对象。只有被标记已经死亡的对象,GC才会在执行垃圾回收时,才会释放掉其占用的内存,这个阶段就被称为垃圾标记阶段

在JVM内部,判断对象是否存活主要是通过两种方式:引用计数算法可达性分析算法

2.1.1,引用计数算法

这种算法就是会为每一个对象保存一个引用计数器属性,如对于一个对象A,只要有任何一个对象引用了A,那么这个A对应的计数器就会加1,当引用失效计数器就会减1。只有引用计数器的值为0时,表示不再被任何变量引用,那么该对象就会被标记,后续会根据是否标记进行回收。

优点是实现比较简单,垃圾对象便于识别,并且其效率比较高;缺点是需要单独的字段存储计数器,需要一定的空间开销,并且计数器需要加减运算操作,增加了时间开销,最主要的是无法处理循环引用的问题,因此Java并没有选择这种算法。

public class A{
    public A a = null;
    List<A> list = new ArrayList();
    public static void main(String[] args) {
        A objectA = new A();
        A objectB = new A();
        //这两个对象相互引用,俩个计数器都+1,导致无法回收
        objectA.a = objectB;
        objectB.a = objectA;
    }
}

2.2.2,可达性分析算法

相对于引用计数器而言,可达性分析算法不仅具有简单和执行高效等特点,更重要的是可以有效地解决这个循环引用的问题,从而防止出现内存泄漏

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VnXrU94q-1681959175717)(img/1681701973152.png)]

通过上图可知,可达性分析算法是以根对象集合为起点,按照从上到下的方式搜索根对象集合所连接的目标是否可达,内存中的存活对象都会被根对象集合直接或者间接连接着,如GC roots和obj1是直接连接着的,和2,3,4是间接连接着的,这整个连接路径被称为引用链。如果目标对象没有任何引用链相连,如6,7,8,则是不可达的,就意味着该对象以及死亡,可以标记为垃圾对象。

在java中,常被用作GC对象的有以下几种:方法中的参数、局部变量、静态属性、字符串常量池引用、同步锁持有的对象、基本数据类型对应的Class对象、异常对象、本地缓存等等。

在使用这个可达性分析算法来判断内存是否可以进行回收,在分析工作时必须在一个能保障一致性的快照中进行,不允许在分析时出现动态的垃圾的增加等,这样才能保证分析结果的准确性。但是也正是因为这个快照的问题,让stw的出现不可避免。

3,JProfiler查看GC Root

查看GC Root有好几种方式,如使用MAT等,但是MAT要涉及到eclipse这些,因此废弃MAT。这里主要是通过这个 JProfiler 这个工具,可以直接在idea中搜索这个插件安装,然后重启idea即可。

在这里插入图片描述

除了这里安装之外,最好再安装一个 .exe 的可执行文件,可以参考黄莹这位大佬写的,这里面有免费JProfiler下载: https://blog.csdn.net/weixin_42311968/article/details/120726106 下载完之后一直点下去,安装,我这里是先使用免费10天的。

安装完成之后,再回到idea,点击右上角的JProfile的图标

在这里插入图片描述

然后在提示框中,输入刚刚 .exe安装路径下面的bin目录下面的 .exe,然后保存即可,再次点击就可以直接使用了

//如我这边安装目录是在D盘下,因此找到这个路径下面的 JProfiler.exe 文件即可
D:\environment\jprofiler\jprofiler11\bin

然后下一步也是那个大佬里面写的,将JVM exit action的参数改成如以下图所示即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9H08THq7-1681959175720)(img/1681808812105.png)]

再点击ok之后,那么这个画面就有了,工具基本就可以使用了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9N6FxTNm-1681959175721)(img/1681809199238.png)]

一段时间之后,就会出现如下画面,其画面是动态的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3KeL8hja-1681959175721)(img/1681810080320.png)]

在Live memory下的All Objects中监视着所有的内存情况,和之前谈到的JVisualVM的功能都是类似的,如之前谈到查看这个字符串常量池到底存在哪就是通过这个方式举的例子。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2hyQPQKg-1681959175722)(img/1681809814749.png)]

如果出现OOM,可以直接通过查看这个Heap Walker目录下的对象信息,来确定是哪个对象发生的OOM,以及是否出现大对象等问题。

4,垃圾回收相关算法

上面讲述了两种方式找出垃圾,接下来就需要将找出的垃圾给清除掉,释放无用对象的内存空间,以便有足够的可用内存为新对象的分配。在jvm中,比较常见的三种垃圾回收算法有:标记清除算法、复制算法、标记压缩算法

4.1,标记清除算法

当堆中有效的内存空间被耗尽的时候,会停止整个程序,简称stw(stop the world),这样可以防止在标记回收的和清除的时候又有新的垃圾出现。

在这里面主要进行两箱工作,第一项是标记,第二项是清除。标记是从根节点开始,标记所有的引用对象,一般是可达对象;清除是从头到尾线性遍历,发现某个对象没有标记为可达对象,则将其回收。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mT2u9H5O-1681959175723)(img/1681871396273.png)]

如上图,绿色部分表示存活对象,黑色表示垃圾对象,白色表示空闲对象,然后从根节点出发,判断对象是否可达,从而确定对象是否需要被回收,最后将黑色对应的对象回收即可,从而实现这个标记清除算法。

该算法的优点是简单易理解。但是缺点也很明显,效率较低;并且在GC的时候,需要停止整个应用程序(stw),用户体验差;最主要的是会产生大量的内存碎片,因此在内部需要维护一个空闲列表。这里的清除并不是直接将对象清除,而是将要清除对象的地址加入到空闲列表里面,然后记录指向要被清除对象的指针,后面来新的对象之后,则将这个空闲列表记录的指针指向新来的这个对象。

4.2,复制算法

针对标记清除的算法的缺陷,如会产生内存碎片,因此这种复制算法诞生。

其核心思想就是将内存空间分成两块,每次只使用其中的一块,在垃圾回收的时候将正在使用的内存中的存活的对象复制到未被使用的内存中,之后再将正在使用的内存中的对象清除,再交换两个内存的角色,最后完成垃圾回收

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YmNZmPj3-1681959175723)(img/1681879548891.png)]

这里的复制是将完整的对象复制,在新生代中存活区的s0区和s1区就是实现了这种算法,经典以空间换时间。并且在后期分配对象时,可以直接使用指针碰撞算法。

复制算法的优点是:没有标记和清除的过程,简单实现,运行高效,并且解决了碎片化的问题。

复制算法的缺点是:需要两倍的内存空间,如果垃圾多,那么需要移动的次数也多,影响效率。

4.3,标记整理算法

复制算法效率虽然高,但是更加的适合新生代中使用,因为那里的对象朝生夕死,那么需要复制移动的对象就不会太多,也就不会太影响效率。但是复制算法不适合在老年代使用,因为里面的对象基本是存活的,那么真要复制移动起来,那么就会严重影响效率,那么这种算法的代价就会比较高。

而标记清除算法会产生垃圾碎片,显然也不能在这个老年代使用,因为如果出现一个大对象这就可能出现放不下的情况,因此就出现了一种新的算法,标记整理法。这种算法就是在标记清除这种算法之上进行了优化的一种算法,从而解决这种内存碎片的问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DtDj66pf-1681959175724)(img/1681885073399.png)]

这种核心思想就是通过根节点开始标记所有能被引用的对象,然后将所有存活的对象按顺序排放,再清理掉没被引用的垃圾。标记整理算法的最终效果就是等同于标记清除之后,再进行一次碎片管理,一次也可以称为 标记-清除-压缩 算法,该算法也不需要使用空闲列表来记录碎片。

标记整理算法的优点是:解决标记清除碎片化问题,复制算法空间问题

标记整理算法的优点是:效率低于复制算法,移动对象的同时需要移动对象引用,移动过程需要stw

4.4,三种算法总结

从效率上来说,复制算法的效率最高,但是会浪费大量的内存。因此兼顾速度,空间开销,是否需要移动对象三个指标来说,标记整理算法相对来说更为稳定,但是效率上不尽人意,因为他比复制算法多了一个标记阶段,比标记清除算法多了一个整理内存的阶段。

5,垃圾回收相关概念

5.1,System.gc() 的理解

默认情况下,通过这个System.gc()的调用,就会显式的触发这个Full GC,同时对这个老年代和新生代进行回收,尝试释放被丢弃的对象所占用的内存。

但是这个System.gc()会调用一个附带的免责声明,就是说这个确实可以触发这个Full GC,但是垃圾回收器会不会做出具体的响应,已经响应的时间是否即时很难保证,有可能并不会响应这次请求,也可能在很长时间后才触发,导致想清除的对象复活或者迟迟不能回收导致OOM的情况。

垃圾回收一般是可以自动进行的,无需手动触发,否则就太过于麻烦了。但是在测试性能的基准的时候,可以在运行期间调用这个System.gc()。

/**
 * @author zhenghuisheng
 * @date : 2023/4/19
 */
public class Test {
    public static void main(String[] args) {
        User user = new User();
        //提醒Jvm进行垃圾回收
        System.gc();
        //强制执行
        //System.runFinalization();
    }
	
    //触发了垃圾回收就会调用这个finalize()
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("触发了垃圾回收");
    }
}

通过上述代码可以得知,在System.gc()之后,有时会触发有时不会触发这个full GC,但是使用这个System.runFinalization()方法时可以保证一定会触发这个 FULL GC的,因为他是强制执行的。

5.2,内存溢出和内存泄漏

5.2.1,内存溢出(OOM)

由于GC的技术一直不断地完善和发展,因此在一般的情况下是不会出现OOM的,除非应用程序所占的内存增长速度非常快,造成垃圾回收已经跟不上内存消耗的速度,这样才可能出现OOM。GC会进行各种年龄段的垃圾回收,在出现OOM之前也会触发一次FULL GC的操作,这时候会回收大量的内存,如果在回收大量的内存之后还不够用,那么就会出现OOM的问题。在java文档中对OutOfMemoryError的解释是这样的:没有空闲内存,并且垃圾收集器也无法提供更多的内存

而内存不够的原因,有可能是Java虚拟机堆内存设置的不够;也可能是创建了大量的大对象,并且对象被引用着,不能被回收,或者对象的大小直接超过堆内存的对大值。

5.2.2,内存泄漏

指的是对象不再被程序使用,但是GC又回收不了这些对象,就被称为内存泄漏。如一些静态对象,其生命周期比较长,但是这些对象关联了一些只用一次的对象或者一些资源对象,而资源对象没关,如mysql连接等,总而导致出现这个内存泄漏。

5.3,Stop The World

简称STW,指的是在触发这个GC时间之后,会产生程序的停顿,就是会让全部的用户线程暂停,没有任何响应,有点像卡死的感觉。在触发这个STW时,需要保证其工作在一个快照中进行,从而保证数据的一致性,如果在分析过程中出现对象还在不断的动态变化着,则最后的分析结果的准确性很难保证。

在被STW中断的应用程序会在GC之后恢复,然而频繁的中断会让用户感觉到卡顿的情况,让用户的体验不友好,因此在后续的优化中,STW就是重点要关注的对象。并且STW是在后台自动的发起和自动的完成的,会在用户不可见的情况下,强行的把用户正常的线程给全部停掉。因此在开发中也要少用System.gc(),否则也容易触发这个STW。

5.4,引用

当内存空间还足够时,可以保留在内存中,如果内存空间在垃圾收集之后还是很紧张,则可以抛弃这些对象,这些对象就被称为引用。

强引用(StrongReference):指在代码中普遍存在的引用赋值,如通过new一个对象,无论在任何情况下,只要强引用的关系还在,垃圾收集器就永远不会回收掉引用的对象。强引用的对象基本是可触及的,即rootGc是可达的,同时强引用也是内存泄漏的主要原因之一。

StringBuffer sbu = new StringBuffer("zhenghuisheng");

软引用(SoftReference):在系统将要发生内存溢出之前,会将这些回想列入回收范围之中进行第二次回收,如果第一次回收之后(回收GC Root不可达的对象)还没有足够的空间,那么第二次回收就会回收这些对象,第二次回收之后还是内存空间不足,那么就会抛出内存溢出的异常。如一些缓存,就是典型的使用了软引用

//声明一个强引用
Object obj = new Object();
//实例化一个软引用
SoftReference<Object> sf = new SoftReference(obj);
obj = null;

弱引用(WeakReference):只被弱引用关联的对象只能生存到下一次垃圾回收之前,当垃圾回收器工作时,无论空间是否足够,都会被回收。弱引用也可以用来作为缓存使用

//声明一个强引用
Object obj = new Object();
//实例化一个弱引用
WeakReference<Object> sf = new WeakReference(obj);
obj = null;

虚引用(PhantomReference):一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚拟引用来获取一个对象的实例。设置一个虚引用关联的唯一目的是在这个对象被收集器回收时收到一个系统通知

//声明一个强引用
Object obj = new Object();
//引用队列
ReferenceQueue ReferenceQueue = new ReferenceQueue();
//实例化一个虚引用
PhantomReference<Object> sf = new PhantomReference(obj,ReferenceQueue);
obj = null;

总结来说:强引用默认是不回收,软引用是内存不足则回收,弱引用是发现即回收,虚引用是用于对象回收追踪

如若转载,请附上转载链接地址:https://blog.csdn.net/zhenghuishengq/article/details/130261481

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为什么许多人吐槽C++11,那些语法值得我们学习呢?

致前行的人&#xff1a; 人生像攀登一座山&#xff0c;而找寻出路&#xff0c;却是一种学习的过程&#xff0c;我们应当在这过程中&#xff0c;学习稳定冷静&#xff0c;学习如何从慌乱中找到生机。 目录 1.C11简介 2.统一的列表初始化 2.1 &#xff5b;&#xff5d;初始化 …

git 常用命令及遇到问题

自己没事&#xff0c;把git常用命令做个记录总结。方便自己和初学者查看&#xff0c;本文针对初学者&#xff0c;如果你已经是工作多年高手&#xff0c;请跳过。 git的几个区认识&#xff0c;分别为工作区&#xff0c;缓存区&#xff0c;版本库。 工作区&#xff1a;包含.git…

【Unity VR开发】结合VRTK4.0:添加碰撞忽略器

语录&#xff1a; 最远的旅行&#xff0c;是从自己的身体到自己的心&#xff0c;是从一个人的心到另一个人的心。坚强不是面对悲伤不流一滴泪&#xff0c;而是擦干眼泪后微笑面对以后的生活。 前言&#xff1a; 模块化提供了一种允许两个或者多个对象忽略彼此碰撞的方法&#x…

揭秘移动云大会展区前沿科技

2023年4月25日-26日 我们苏州金鸡湖国际会议中心见&#xff01; 1场重磅主论坛、10场分论坛、2600㎡展区 数字中国新未来 尽在2023移动云大会 2023移动云大会设有中国移动和合作伙伴两大展区&#xff0c;联合40余家优质合作伙伴&#xff0c;全方位展示移动云在自主能力、行…

vue yarn npm

2016年左右 &#xff0c;facebook针对npm包管理工具存在的性能问题进行了针对性开发并发布了yarn新的node包开发管理工具&#xff0c;具体对比&#xff0c;同学们自行网上搜索资料对比。 配置 1、先下载好NodeJS&#xff0c;然后输入如下命令安装yarn npm install -g yarn 2、…

如何微调Segment Anything Model

文章目录 什么是SAM&#xff1f;什么是模型微调&#xff1f;为什么要微调模型&#xff1f;如何微调 Segment Anything 模型背景与架构创建自定义数据集输入数据预处理训练设置循环训练保存检查点并从中启动模型 下游应用程序的微调 随着 Meta 上周发布的 Segment Anything Mode…

线程等待其他线程执行同步类CountDownLatch

文章目录 前言核心原理源码解析同步源码分析await源码分析countDown源码分析 实战演示1、创建演示代码2、创建测试用例3、测试结果演示 写在最后 前言 大家都知道多线程在我们实际编码过程中运用很多&#xff0c;很多情况我们需要靠多线程来提升系统性能。但是有些时候我们需要…

C语言开发环境搭建及调试

C简介 可移植 标准C C/C &#xff08;系统硬件操作的接口&#xff0c;windows&#xff0c;Linux不一样&#xff09; 跨平台 Java Python 下载 去官网选择Visual Studio 2019下载 安装过程中勾选使用C的桌面开发 安装好之后点击创建新项目——空项目 位置最好放在根目录下&…

【vue2】近期bug收集与整理02

⭐【前言】 在使用vue2构建页面时候&#xff0c;博主遇到的问题难点以及最终的解决方案。 &#x1f973;博主&#xff1a;初映CY的前说(前端领域) &#x1f918;本文核心&#xff1a;博主遇到的问题与解决思路 目录 ⭐数据枚举文件的使用⭐elementUI中分页组件使用的注意事项⭐…

OpenAI-ChatGPT最新官方接口《从0到1生产最佳实例》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(十一)(附源码)

Production Best Practices 生产最佳实例 前言Introduction 导言Setting up your organization 设置您的组织Managing billing limits 管理计费限额API keys API密钥Staging accounts 演示账户 Building your prototype 构建您的原型Additional tips 其它技巧 Techniques for i…

C++函数重载

目录 函数重载函数重载是怎样实现的 函数重载 函数重载&#xff1a;是函数的一种特殊情况&#xff0c;C允许在同一作用域中声明几个功能类似的同名函数&#xff0c;这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同&#xff0c;常用来处理实现功能类似数据类型不同的…

找PPT模板就上这5个网站~

分享几个可以永久免费下载PPT模板、素材的网站&#xff0c;上万个模板随便下载&#xff0c;赶紧收藏起来~ 1、菜鸟图库 https://www.sucai999.com/search/ppt/0_0_0_1.html?vNTYxMjky 网站素材非常全面&#xff0c;主要以设计类素材为主&#xff0c;办公类素材也很多&#x…

Spring MVC 接收 json 和返回 json (14)

目录 总入口 测试case 源码分析 1. 针对RequestBody的参数解析 2. 针对 ResponseBody 的返回值处理 总入口 通过上一篇Spring MVC 参数解析&#xff08;13&#xff09;_chen_yao_kerr的博客-CSDN博客的说明&#xff0c;相信大家对Sping MVC的参数解析有了一定的了解&…

8. 优先队列

8. 优先队列 普通的队列是一种先进先出的数据结构&#xff0c;元素在队列尾追加&#xff0c;而从队列头删除。在某些情况下&#xff0c;我们可能需要找出队列中的最大值或者最小值&#xff0c;例如使用一个队列保存计算机的任务&#xff0c;一般情况下计算机的任务都是有优先级…

【有功-无功协调优化】基于改进多目标粒子群优化算法(小生境粒子群算法)的配电网有功-无功协调优化研究(Matlab代码实现)

&#x1f4a5; &#x1f4a5; &#x1f49e; &#x1f49e; 欢迎来到本博客 ❤️ ❤️ &#x1f4a5; &#x1f4a5; &#x1f3c6; 博主优势&#xff1a; &#x1f31e; &#x1f31e; &#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 …

中断嵌套实验

使用汇编语言&#xff0c;要求&#xff1a; 外部中断1可以嵌套外部中断0 没有中断时&#xff0c;8个LED发光二极管以0.1s的速度闪烁。 有外部中断0时&#xff0c;8个LED发光二极管以0.1s的速度流水点亮。&#xff08;中断子程序0&#xff09; 有外部中断1时&#xff0c;会打断外…

gdb调试常用指令及案例讲解

文章目录 前言一、常用指令二、案例说明1、测试源文件2、编译和调试 三、其他指令四、案例说明 前言 GDB是一个由GNU开源组织发布的、UNIX/LINUX 操作系统下的、基于命令行的、功能强大的程序调试工具。 GDB 支持断点、单步执行、打印变量、观察变量、查看寄存器、查看堆栈等调…

每天一道大厂SQL题【Day22】华泰证券真题实战(四)

每天一道大厂SQL题【Day22】华泰证券真题实战(四) 大家好&#xff0c;我是Maynor。相信大家和我一样&#xff0c;都有一个大厂梦&#xff0c;作为一名资深大数据选手&#xff0c;深知SQL重要性&#xff0c;接下来我准备用100天时间&#xff0c;基于大数据岗面试中的经典SQL题&…

2023软件测试工程师必备技能?要卷,谁还不会了......

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 软件测试岗位是怎…

day15 消息队列

目录 消息队列 消息队列的使用 发送消息 消息的接收 消息队列的控制 消息队列 概念&#xff1a; 消息队列是system V IPC对象的一种&#xff1b; 消息队列有消息队列ID来唯一标识&#xff1b; 消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等&a…