当前位置: 首页 > news >正文

从零开始理解JVM:对象的生命周期之对象销毁(垃圾回收)

一、JVM参数

在学垃圾回收器之前,我们先要知道,jvm参数是怎么回事。因为配置各种回收器,必须对应各种参数设置。

  • 标准参数(-)

    所有的JVM实现都必须实现这些参数的功能,而且向后兼容

    • -help
    • -version
  • 非标准参数(-X)

    默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容

    • -Xint 解析模式运行,启动很快,执行稍慢
    • -Xcomp 纯编译模式运行,执行很快,启动很慢
    • -Xmixed 混合模式,开始解释执行,启动速度较快,对热点代码实行检测和编译。默认此模式
  • 非Stable参数(-XX)

    各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用

    • -XX:newSize
    • -XX:+UseSerialGC

jvm的标准参数,一般都是很稳定的,在未来的JVM版本中不会改变。

jvm的-X参数是非标准参数,也就意味着,在不同版本的jvm中,参数可能会有所不同

[root@node01 test]# java -X-Xmixed           混合模式执行 (默认)  #了解!-Xint             仅解释模式执行  #了解!-Xbootclasspath:<用 : 分隔的目录和 zip/jar 文件>设置搜索路径以引导类和资源-Xbootclasspath/a:<用 : 分隔的目录和 zip/jar 文件>附加在引导类路径末尾-Xbootclasspath/p:<用 : 分隔的目录和 zip/jar 文件>置于引导类路径之前-Xdiag            显示附加诊断消息-Xnoclassgc       禁用类垃圾收集-Xincgc           启用增量垃圾收集-Xloggc:<file>    将 GC 状态记录在文件中 (带时间戳)-Xbatch           禁用后台编译-Xms<size>        设置初始 Java 堆大小     #掌握!-Xmx<size>        设置最大 Java 堆大小     #掌握!-Xss<size>        设置 Java 线程堆栈大小   #掌握!-Xprof            输出 cpu 配置文件数据-Xfuture          启用最严格的检查, 预期将来的默认值-Xrs              减少 Java/VM 对操作系统信号的使用 (请参阅文档)-Xcheck:jni       对 JNI 函数执行其他检查-Xshare:off       不尝试使用共享类数据-Xshare:auto      在可能的情况下使用共享类数据 (默认)-Xshare:on        要求使用共享类数据, 否则将失败。-XshowSettings    显示所有设置并继续-XshowSettings:all显示所有设置并继续-XshowSettings:vm 显示所有与 vm 相关的设置并继续-XshowSettings:properties显示所有属性设置并继续-XshowSettings:locale显示所有与区域设置相关的设置并继续-X 选项是非标准选项, 如有更改, 恕不另行通知。

 -XX参数也是非标准参数,主要用于改变jvm的一些基础行为,比如垃圾回收行为、jvm的调优、输出debug调试信息等。

#行为参数(功能开关)
-XX:-DisableExplicitGC  禁止调用System.gc();但jvm的gc仍然有效
-XX:+MaxFDLimit 最大化文件描述符的数量限制
-XX:+ScavengeBeforeFullGC   新生代GC优先于Full GC执行
-XX:+UseGCOverheadLimit 在抛出OOM之前限制jvm耗费在GC上的时间比例
-XX:-UseConcMarkSweepGC 对老生代采用并发标记交换算法进行GC
-XX:-UseParallelGC  启用并行GC
-XX:-UseParallelOldGC   对Full GC启用并行,当-XX:-UseParallelGC启用时该项自动启用
-XX:-UseSerialGC    启用串行GC
-XX:+UseThreadPriorities    启用本地线程优先级#性能调优
-XX:LargePageSizeInBytes=4m 设置用于Java堆的大页面尺寸
-XX:MaxHeapFreeRatio=70 GC后java堆中空闲量占的最大比例
-XX:MaxNewSize=size 新生成对象能占用内存的最大值
-XX:MaxPermSize=64m 老生代对象能占用内存的最大值
-XX:MinHeapFreeRatio=40 GC后java堆中空闲量占的最小比例
-XX:NewRatio=2  新生代内存容量与老生代内存容量的比例
-XX:NewSize=2.125m  新生代对象生成时占用内存的默认值
-XX:ReservedCodeCacheSize=32m   保留代码占用的内存容量
-XX:ThreadStackSize=512 设置线程栈大小,若为0则使用系统默认值
-XX:+UseLargePages  使用大页面内存#调试参数
-XX:-CITime 打印消耗在JIT编译的时间
-XX:ErrorFile=./hs_err_pid<pid>.log 保存错误日志或者数据到文件中
-XX:-ExtendedDTraceProbes   开启solaris特有的dtrace探针
-XX:HeapDumpPath=./java_pid<pid>.hprof  指定导出堆信息时的路径或文件名
-XX:-HeapDumpOnOutOfMemoryError 当首次遭遇OOM时导出此时堆中相关信息
-XX:OnError="<cmd args>;<cmd args>" 出现致命ERROR之后运行自定义命令
-XX:OnOutOfMemoryError="<cmd args>;<cmd args>"  当首次遭遇OOM时执行自定义命令
-XX:-PrintClassHistogram    遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同
-XX:-PrintConcurrentLocks   遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同
-XX:-PrintCommandLineFlags  打印在命令行中出现过的标记
-XX:-PrintCompilation   当一个方法被编译时打印相关信息
-XX:-PrintGC    每次GC时打印相关信息
-XX:-PrintGCDetails    每次GC时打印详细信息
-XX:-PrintGCTimeStamps  打印每次GC的时间戳
-XX:-TraceClassLoading  跟踪类的加载信息
-XX:-TraceClassLoadingPreorder  跟踪被引用到的所有类的加载信息
-XX:-TraceClassResolution   跟踪常量池
-XX:-TraceClassUnloading    跟踪类的卸载信息
-XX:-TraceLoaderConstraints 跟踪类加载器约束的相关信息

上面列举了很多JVM参数,我们不需要记,而是用到的时候知道怎么查就行了,我们在接下来的介绍中就会用到一些上面的参数,如有不懂得,可以上来查 

二、垃圾回收

回收事件三要素

在哪收(地点)

  • 程序计数器、jvm虚拟机栈、本地方法栈,这些随着线程诞生和消亡,线程释放它就释放,无需回收。

  • 方法区,这里是一些类信息和静态变量,也有回收的可能性,但是很鸡肋,收不回多少东西。

    实际上,虚拟机规范也并不强制要求回收这里。

  • 堆,这才是大头。因为运行期频繁创建和丢弃对象的事件都在这里发生!

什么时候收(时间)

  • 在堆内存存储达到一定阈值之后  

    当年轻代或者老年代达到一定阈值,Java虚拟机无法再为新的对象分配内存空间了,那么Java虚拟机就会触发一次GC去回收掉那些已经不会再被使用到的对象

  • 主动调用System.gc() 后尝试进行回收

    手动调用System.gc()方法,通常这样会触发一次的Full GC,所以一般不推荐这个东西的使用,你会干扰jvm的运作

回收谁(人物)

回收谁?哪些对象能够被回收,哪些还不能?总得有个判断标准。

在编程语言界,有两种办法判定一个对象是否已消亡:

1)引用计数法

假设有一个对象A,任何一个对象对A的引用,那么对象A的引用计数器+1,当引用失败时,对象A的引用计数器就-1,如果对象A的计数器的值为0,就说明对象A没有引用了,可以被回收。

优点:

  • 实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,就可以直接回收。
  • 在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报outofmember 错误。
  • 区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象。

缺点:

  • 每次对象被引用时,都需要去更新计数器,有一点时间开销。
  • 浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
  • 无法解决循环引用问题。(最大的缺点)

这个了解即可,因为JVM没采用这个方法

2)可达性分析

通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”,如果某个对象到GC Roots间没有任何引用链相连,就说明从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的,就是可以回收的对象。

在JVM虚拟机中,可作为GC Roots的对象包括以下几种:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象(重点)
  • 在方法区中类静态属性引用的对象(类变量)。(重点)
  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。(重点)
  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
  • 所有被同步锁(synchronized关键字)持有的对象。(重点)
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
  • 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

再谈对象的四类引用

  • 强引用

    • 在程序代码之中普遍存在的引用赋值,即类似“Object obj=new Object()”这种引用关系。
    • 无论任何情况下,内存用不回收,够就够,不够抛内存溢出异常。
  • 软引用

    • 用来描述一些还有用,但非必须的对象。被SoftReference包装的那些类
    • 先回收没用的对象,收完后发现还不够,再触发二次回收,对软引用对象下手。
  • 弱引用

    • 用来描述那些非必须对象,强度比软引用更弱。被WeakReference包装的那些类
    • 无论当前内存是否足够,垃圾收集一旦发生,弱引用直接回收。
  • 虚引用(实际开发基本不用)

    • 最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。
    • 为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。

三、回收算法(策略)

标记清除法

标记清除算法,是将垃圾回收分为2个阶段,分别是标记和清除。

  • 标记:从根节点开始标记引用的对象。
  • 清除:未被标记引用的对象就是垃圾对象,清理掉。

  • 执行效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要停止应用程序,对于交互性要求比较高的应用而言这个体验是非常差的。
  • 通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收的对象可能存在于内存的各个角落,所以清理出来的内存是不连贯的。

标记压缩算法

也叫标记-整理,标记压缩算法是在标记清除算法的基础之上,做了优化改进的算法。

和标记清除算法一样,也是从根节点开始,对对象的引用进行标记

在清理阶段,并不是简单的清理未标记的对象,而是将存活的对象压缩到内存的一端,然后清理边界以外的垃圾,从而解决了碎片化的问题。可以理解成清除的时候做了内存整理,见下图

  • 该算法解决了标记清除算法的碎片化的问题,下一步分配内存的时候更方便
  • 多了一步整理操作,对象需要移动内存位置,效率也好不到哪去

标记复制算法

复制算法的核心就是,将原有的内存空间一分为二,每次只用其中的一块,在垃圾回收时,将正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收。

优点:

  • 在垃圾对象多的情况下,效率较高,因为要把存活的全部移动一遍
  • 清理后,内存无碎片

缺点:

  • 在垃圾对象比例少的情况下,不适用,如:年轻代这么用可以,老年代就不合适
  • 分配的2块内存空间,在同一个时刻,只能使用一半,内存使用率较低

年轻代的标记复制算法

年轻代内存的回收就是典型的标记复制法

  • sruvivor区有两个,一个from,另一个叫to,这俩交替互换角色
  • 在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。
  • 紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。
  • 年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置) 的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。
  • 经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。
  • GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

分代GC的思想

确切的说,分代不算是一种算法,它是一种解决回收问题的思路:具体情况具体分析

在堆内存中,有些对象短暂存活有些则是长久存活,所以需要将堆内存进行分代,将短暂存活的对象放到一起,进行高频率的回收,长久存活的对象集中放到一起,进行低频率的回收

细粒度的控制不同区域,调节不同的回收频率,节约系统资源(回收期间系统要额外干活的!)。

分代算法其实就是这样的,根据回收对象的特点进行选择,在jvm中,年轻代适合使用复制算法,老年代适合使用标记清除或标记压缩算法。

一些英文单词概念:

Minor GC/Young GC:新生代收集;

Major GC/Old GC:指目标只是老年代的垃圾收集。(CMS收集器)

Mixed GC:指目标是收集整个新生代以及部分老年代的垃圾收集。(G1收集器)

Full GC:所有的内存整理一遍,包括堆和方法区。轻易不要触发

四、回收器(执行者)

前面我们讲了垃圾回收的算法,还需要有具体的实现。

策略有了,谁来执行呢?这事就落到任劳任怨的回收器头上了

在jvm中,实现了多种垃圾收集器,这些收集器种类繁多,看似乱七八糟,其实理清楚后很简单。

1)基本概念术语等

  • 用户线程:java程序运行后,用户不停请求操作jvm内存,这些称为用户线程
  • GC线程:jvm系统进行垃圾回收启动的线程

  • 串行:GC采用单线程,收集时停掉用户线程
  • 并行:GC采用多线程,收集时同样要停掉用户线程
  • 并发:用户线程和GC线程同步进行,这意义就不一样了

  • STW:stop the world ,暂停响应用户线程,只提供给GC线程工作来回收垃圾(很不爽的事情)
  • 分代:垃圾回收器是要工作在某个代上的,可能是年轻代,老年代,有的可能两个代都能工作
  • 组合:因为分代,所以得有组合,你懂得……

2)串行回收器

其实是两个收集器,年轻代的叫 Serial , 老年代的叫 Serial Old,很好记!

这是最基础的,历史最悠久的收集器。

GC时,停掉用户线程,同时,GC本身也是只有一个线程在跑

使用方式 -XX:+UserSerialGC

# 为了测试GC,将堆的初始和最大内存都设置为16M
-XX:+UseSerialGC -XX:+PrintGCDetails -Xms16m -Xmx16m

启动程序,可以看到下面打印出来的详细GC信息

[GC (Allocation Failure) [DefNew: 4416K->512K(4928K), 0.0046102 secs] 4416K->1973K(15872K), 0.0046533 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [Tenured: 10944K->3107K(10944K), 0.0085637 secs] 15871K->3107K(15872K), [Metaspace: 3496K->3496K(1056768K)], 0.0085974 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
  • DefNew

    • 表示使用的是串行垃圾收集器。
  • 4416K->512K (4928K)

    • 表示,年轻代GC前,占有4416K内存,GC后,占有512K内存,总大小4928K
  • 0.0046102 secs

    • 表示,GC所用的时间,单位为秒。
  • 4416K->1973K (15872K)

    • 表示,GC前,堆内存占有4416K,GC后,占有1973K,总大小为15872K
  • Full GC

    • 表示,内存空间全部进行GC,老年代、元空间

3)并行回收器

  • ParNew回收器:

    新生代的,无非就是将Serial的单线程换成多线程,它现在存在的唯一价值就是作为新生代收集器配合老年代的CMS收集器一起工作,并且在jdk9里也已不再推荐这套组合,而是推荐G1。

    我们只需要知道的是:曾经,它存在过。

  • 另外一对并行回收器:

    Parallel Scavenge (新生代的) / Parallel Old (老年代的)

  • -XX:+UseParallelGC

    • 年轻代使用ParallelGC垃圾回收器,老年代使用串行回收器。
  • -XX:+UseParallelOldGC

    • 年轻代使用ParallelGC垃圾回收器,老年代使用ParallelOldGC垃圾回收器。
#打印的信息
[GC (Allocation Failure) [PSYoungGen: 4096K->480K(4608K)] 4096K->1840K(15872K), 0.0034307 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Ergonomics) [PSYoungGen: 505K->0K(4608K)] [ParOldGen: 10332K->10751K(11264K)] 10837K->10751K(15872K), [Metaspace: 3491K->3491K(1056768K)], 0.0793622 secs] [Times: user=0.13 sys=0.00, real=0.08 secs] 

PSYoungGen:年轻代,Parallel Scavenge

ParOldGen:老年代,Parallel Old

4)并发 - CMS

CMS收集器,工作在老年代。 ParNew

前面的收集器都是要停止用户线程的,而CMS收集器这是真正意义上的并行处理器,也就是用户线程和GC线程在同一时间一起工作。

  • 初始化标记 :标记root直接关联的对象(只扫描可达性分析中的第一层根节点),会导致stw,但是这个没多少对象,时间短
  • 并发标记:沿着上一步的root,往下追踪,这步耗时最长,但是与用户线程同时运行
  • 重新标记:因为上一步是并发进行的,所以再增量过一遍有变化的,会导致stw,但比上一步少很多
  • 并发清理:标记完的干掉,因为是标记-清除算法,不需要移动存活对象,所以这一步与用户线程同时运行
  • 重置线程:重置状态等待下次CMS的触发,与用户线程同时运行
#设置启动参数
-XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -Xms16m -Xmx16m
#运行日志
#注意,cms默认搭配的新生代是 parnew :
[GC (Allocation Failure) [ParNew: 4926K->512K(4928K), 0.0041843 secs] 9424K->6736K(15872K), 0.0042168 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] #老年代开始:
#第一步,初始标记
[GC (CMS Initial Mark) [1 CMS-initial-mark: 6224K(10944K)] 6824K(15872K), 0.0004209 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
#第二步,并发标记
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
#第三步,预处理
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
#第四步,重新标记
[GC (CMS Final Remark) [YG occupancy: 1657 K (4928 K)][Rescan (parallel) , 0.0005811 secs][weak refs processing, 0.0000136 secs][class unloading, 0.0003671 secs][scrub symbol table, 0.0006813 secs][scrub string table, 0.0001216 secs][1 CMS-remark: 6224K(10944K)] 7881K(15872K), 0.0018324 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
#第五步,并发清理
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.004/0.004 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
#第六步,重置
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

优点:

  • 不可否认,一款优秀的收集器,并发收集,低停顿。
  • 互联网服务器上低停顿的现实要求很吻合,一个网站总不能告诉用户你用10分钟,歇会再来用。

但是,CMS也不是完美的:

  • 它不能等到内存吃紧了才启动收集。因为收集期间用户线程还在跑,得预留。
  • 浮动垃圾干不掉,在并发标记、并发清理时,产生的新垃圾必须到下一次收集时处理。
  • 标记-清除算法,免不了产生碎片,可以开启压缩但这些参数在jdk9里也已废弃掉
  • 最后,搭配CMS的年轻代现在只剩下了ParNew,是那么的苍白无力。实际上,jdk9开始已经把它逐步淘汰

5)并发 - G1

G1 的主要目标是提供一种低延迟的垃圾收集方案,适用于大堆内存的应用程序。G1 收集器通过将堆内存划分为多个小的区域(Region),并采用并发和增量的方式进行垃圾收集,从而实现高效的内存管理。

这些region可以是Eden、Survivor、Old、Humongous(专门存大对象的老年区)

这些区在物理地址上不再连续。而是把整个物理地址分成一个个大小相等的region,每一个region可以是上面角色中的一个,还可以在某个时刻转变角色,从eden变成old !(就是个标签)

这样收集的时候,它收集某些性价比高的region回收就可以了。所以某个时刻,G1可能连老带少一起收拾。

那它是怎么做的呢?收拾哪些region呢?

先看两个概念,容易搞混:

  • Remembered Set:记忆集,简称RS,每个 Region关联一个。RS 比较复杂,简单来说就是记录Region之间对象的引用关系。

  • Collection Set:简称CSet,在一次收集中,那些性价比高的Region揪出来组成一个回收集,将来一口气回收掉。这个集合里是筛选出来的一些Region

    至于Region里面剩下的存活的对象,多个Region压缩到一个空闲Region里去,这样就完成了一次收集。

G1中提供了三种模式垃圾回收模式,Young GC、Mixed GC 和 Full GC,在不同的条件下被触发。

所谓的模式,其实也就是G1收集的时候,Region选哪种,是只选年轻代的Region?还是两种都筛选?

  • Young GC

选定所有年轻代里的Region。通过控制年轻代的region个数,即年轻代内存大小,来控制young GC的时间开销。

  • Mixed GC

选定所有年轻代里的Region,外加统计的在用户指定的开销目标范围内选择收益高的老年代Region。

  • full GC

严格意义上讲,这不属于G1的模式。但是使用G1时是有可能发生的。

当mixed GC实在无法跟上程序分配内存的速度,导致老年代填满无法继续进行Mixed GC,就会改为使用serial old GC(full GC)来收集整个堆。

  • 初始标记:标记出 GC Roots 直接关联的对象,这个阶段速度较快,STW,单线程执行。

  • 并发标记:从 GC Root 开始对堆中的对象进行可达新分析,找出存活对象,这个阶段耗时较长,但可以和用户线程并发执行。

  • 重新标记:修正在并发标记阶段因用户程序执行而产生变动的标记记录。STW,并发执行。

  • 筛选回收:筛选回收阶段会对各个 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划,筛出CSet后移动合并存活对象到空Region,清除旧的,完工。因为这个阶段需要移动对象内存地址,所以必须STW。

    思考一下,这属于什么算法呢???

    答:从Region的动作来看G1使用的是标记-复制算法。而在全局视角上,类似标记 - 整理

总结:

G1前面的几步和CMS差不多,只有在最后一步,CMS是标记清除,G1需要合并Region属于标记整理

优缺点

  • 并发性:继承了CMS的优点,可以与用户线程并发执行。当然只是在并发标记阶段。其他还是需要STW
  • 分代GC:G1依然是一个分代回收器,但是和之前的各类回收器不同,它同时兼顾年轻代和老年代。而其他回收器,或者工作在年轻代,或者工作在老年代;
  • 空间整理:G1在回收过程中,会进行适当的对象移动,不像CMS只是简单地标记清理对象。在若干次GC后,CMS必须进行一次碎片整理。而G1不同,它每次回收都会有效地复制对象,减少空间碎片,进而提升内部循环速度。
  • 可预见性:为了缩短停顿时间,G1建立可预存停顿的模型,这样在用户设置的停顿时间范围内,G1会选择适当的区域进行收集,确保停顿时间不超过用户指定时间。

相关文章:

从零开始理解JVM:对象的生命周期之对象销毁(垃圾回收)

一、JVM参数 在学垃圾回收器之前&#xff0c;我们先要知道&#xff0c;jvm参数是怎么回事。因为配置各种回收器&#xff0c;必须对应各种参数设置。 标准参数&#xff08;-&#xff09; 所有的JVM实现都必须实现这些参数的功能&#xff0c;而且向后兼容 -help-version 非标准参…...

计算机网络的发展

目录 起源与早期发展 ARPANET与TCP/IP协议的诞生 互联网的诞生与普及 高速互联网与无线网络的兴起 移动互联网与云计算的崛起 物联网、区块链与自动驾驶技术的兴起 起源与早期发展 计算机网络的雏形最早可以追溯到20世纪60年代&#xff0c;主要是为了共享大型计算资源。当…...

python3 自动更新的缓存类

这个类会在后台自动更新缓存数据&#xff0c;你只需要调用方法来获取数据即可。 自动更新缓存类 以下是 AutoUpdatingCache 类的实现&#xff1a; import threading import timeclass AutoUpdatingCache:def __init__(self, update_function, expiry_time60):""&qu…...

PICO 获取设备号 SN码

Unity版本 2020.3.42f1c1PICO SDK版本PICO Unity Integration SDK-3.0.5-20241105Pico设备pico 4ultra 注意 此api暂时只测试企业版本 pico 4ultra 代码 using Unity.XR.PICO.TOBSupport;private void Awake() {bool result PXR_Enterprise.InitEnterpriseService();Debug.L…...

spf算法、三类LSA、区间防环路机制/规则、虚连接

1.构建spf树&#xff1a; 路由器将自己作为最短路经树的树根根据Router-LSA和Network-LSA中的拓扑信息,依次将Cost值最小的路由器添加到SPF树中。路由器以Router ID或者DR标识。广播网络中DR和其所连接路由器的Cost值为0。SPF树中只有单向的最短路径,保证了OSPF区域内路由计管不…...

计算机基础(下)

内存管理 内存管理主要做了什么&#xff1f; 操作系统的内存管理非常重要&#xff0c;主要负责下面这些事情&#xff1a; 内存的分配与回收&#xff1a;对进程所需的内存进行分配和释放&#xff0c;malloc 函数&#xff1a;申请内存&#xff0c;free 函数&#xff1a;释放内存…...

OpenCV从入门到精通实战(七)——探索图像处理:自定义滤波与OpenCV卷积核

本文主要介绍如何使用Python和OpenCV库通过卷积操作来应用不同的图像滤波效果。主要分为几个步骤&#xff1a;图像的读取与处理、自定义卷积函数的实现、不同卷积核的应用&#xff0c;以及结果的展示。 卷积 在图像处理中&#xff0c;卷积是一种重要的操作&#xff0c;它通过…...

Java基础——(一)Java概述

Java特性 简单性&#xff1a;Java与C很相似&#xff0c;但剔除了C中许多比较复杂并且很少使用的功能&#xff0c;比如头文件、指针运算、结构、联合、操作符重载、虚基类等&#xff0c;从而使Java更易于上手、学习。面向对象&#xff1a;Java是一门面向对象语言&#xff0c;具…...

关于IDE的相关知识之三【插件安装、配置及推荐的意义】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于ide插件安装、配置及推荐意义的相关内容…...

C++设计模式之组合模式的基本结构

组合模式的UML类图表示如下&#xff1a; ------------------ ------------------ | Component | <----- | Leaf | ------------------ ------------------ | operation() | | operation() | ------------------ --…...

Apache OFBiz xmlrpc XXE漏洞(CVE-2018-8033)

目录 1、漏洞描述 2、EXP下载地址 3、EXP利用 1、漏洞描述 Apache OFBiz是一套企业资源计划&#xff08;ERP&#xff09;系统。它提供了广泛的功能&#xff0c;包括销售、采购、库存、财务、CRM等。 Apache OFBiz还具有灵活的架构和可扩展性&#xff0c;允许用户根据业务需求…...

梯度——多元函数偏导数——梯度算子的理论基础

梯度是一个数学概念&#xff0c;在多维空间中表示函数在某一点处变化最快的方向和变化率。 对于一个多元函数 f ( x 1 , x 2 , ⋯ , x n ) f(x_1, x_2, \cdots, x_n) f(x1​,x2​,⋯,xn​)&#xff0c;其梯度是一个向量&#xff0c;记作 ∇ f \nabla f ∇f或者 grad f f f&…...

【GPT】力量训练的底层原理?

详细解读力量训练的每一个底层原理 力量训练之所以有效&#xff0c;是因为它利用了肌肉、神经系统和生物化学反应的基本机制。以下逐一详细解析&#xff0c;并解释相关概念。 1. 应力-恢复-适应理论 概念解析 应力&#xff08;Stress&#xff09;&#xff1a;指训练带来的负…...

Django 路由层

1. 路由基础概念 URLconf (URL 配置)&#xff1a;Django 的路由系统是基于 urls.py 文件定义的。路径匹配&#xff1a;通过模式匹配 URL&#xff0c;并将请求传递给对应的视图处理函数。命名路由&#xff1a;每个路由可以定义一个名称&#xff0c;用于反向解析。 2. 基本路由配…...

Unity项目性能优化列表

1、对象池 2、检查内存是否泄露。内存持续上升(闭包、委托造成泄露) 3、检查DrawCall数量&#xff0c;尽量减少SetPassCall 4、尽量多的利用四种合批 动态合批(Dynamic Batching)静态合批(Static Batching)GPUInstancingSRP Batcher 动态合批消耗内存把多个网格组合在一起合并…...

docker启动kafka、zookeeper、kafdrop

1、启动zookeeper docker run -d --name zookeeper -p 2181:2181 -t wurstmeister/zookeeper2、启动kafka docker run -d --name kafka --publish 9092:9092 --link zookeeper:zookeeper -e KAFKA_BROKER_ID1 -e HOST_IP127.0.0.1 -e KAFKA_ZOOKEEPER_CONNECTzookeeper:2181…...

Pytest使用Jpype调用jar包报错:Windows fatal exception: access violation

问题描述 ​   之前我们有讲过如何使用Jpype调用jar包&#xff0c;在成功调用jar包后&#xff0c;接着在Pytest框架下编写自动测试用例。但是在Pytest下使用Jpype加载jar包&#xff0c;并调用其中的方法会以下提示信息&#xff1a; ​   虽然提示信息显示有Windows显示致命…...

【AI赋能 Python编程】第十一章 Python技能提升指南:借助AI加速学习

AI赋能 Python编程-系列文章目录 第十一章 Python技能提升指南&#xff1a;借助AI加速学习 文章目录 AI赋能 Python编程-系列文章目录第十一章 Python技能提升指南&#xff1a;借助AI加速学习 前言明确学习目标基础入门指导进阶学习指导学习过程互动综合学习提示模板 前言 在…...

️ 爬虫开发中常见的性能优化策略有哪些?

在爬虫开发中&#xff0c;性能优化是确保爬虫稳定、高效运行的关键。以下是一些常见的性能优化策略&#xff0c;结合了搜索结果中的信息&#xff1a; 异步编程&#xff1a; 使用 asyncio 和 aiohttp 实现高并发&#xff0c;提高爬取效率。异步请求允许在等待一个请求完成的同时…...

Ubuntu安装不同版本的opencv,并任意切换使用

参考&#xff1a; opencv笔记&#xff1a;ubuntu安装opencv以及多版本共存 | 高深远的博客 https://zhuanlan.zhihu.com/p/604658181 安装不同版本opencv及共存、切换并验证。_pkg-config opencv --modversion-CSDN博客 Ubuntu下多版本OpenCV共存和切换_ubuntu20如同时安装o…...

《操作系统 - 清华大学》5 -4:虚拟技术

文章目录 0. 虚拟存储的定义1. 目标2.局部性原理3. 虚拟存储的思路与规则4. 虚拟存储的基本特征5. 虚拟页式存储管理5.1 页表表项5.2 示例 0. 虚拟存储的定义 1. 目标 虚拟内存管理技术&#xff0c;简称虚存技术。那为什么要虚存技术&#xff1f;在于前面覆盖和交换技术&#…...

网安瞭望台第5期 :7zip出现严重漏洞、识别网络钓鱼诈骗的方法分享

国内外要闻 7 - Zip存在高危漏洞&#xff0c;请立刻更新 2024 年 11 月 24 日&#xff0c;do son 报道了 7 - Zip 中存在的一个高严重性漏洞 CVE - 2024 - 11477。7 - Zip 是一款广受欢迎的文件压缩软件&#xff0c;而这个漏洞可能会让攻击者在存在漏洞的系统中执行恶意代码。…...

【JS】面试八股文

类型 JavaScript 有哪些数据类型,它们的区别? 答:JavaScript 共有八种数据类型, 分别是 Undefined、 Null、 Boolean、Number、String、Object、Symbol、BigInt。 其中 Symbol是ES6中新增的,BigInt 是 ES2020 中新增的。 Symbol 代表创建后独一无二且不可变的数据类型,…...

1、正则表达式

grep匹配 grep用来过滤文本内容&#xff0c;以匹配要查询的结果。 grep root /etc/passwd&#xff1a;匹配包含root的行 -m 数字&#xff1a;匹配几次后停止 -v&#xff1a;取反-i&#xff1a;忽略字符的大小写&#xff0c;默认的&#xff0c;可以不加-n&#xff1a…...

带有悬浮窗功能的Android应用

android api29 gradle 8.9 要求 布局文件 (floating_window_layout.xml): 增加、删除、关闭按钮默认隐藏。使用“开始”按钮来控制这些按钮的显示和隐藏。 服务类 (FloatingWindowService.kt): 实现“开始”按钮的功能&#xff0c;点击时切换增加、删除、关闭按钮的可见性。处…...

uniapp开发微信小程序笔记8-uniapp使用vant框架

前言&#xff1a;其实用uni-app开发微信小程序的首选不应该是vant&#xff0c;因为vant没有专门给uni-app设置专栏&#xff0c;可以看到目前Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本&#xff0c;并由社区团队维护 React 版本和支付宝小程序版本。 但是我之前维…...

C++软件设计模式之组合模式与其他模式的协作举例

组合模式&#xff08;Composite Pattern&#xff09;、装饰器模式&#xff08;Decorator Pattern&#xff09;、享元模式&#xff08;Flyweight Pattern&#xff09;、迭代器模式&#xff08;Iterator Pattern&#xff09;和访问者模式&#xff08;Visitor Pattern&#xff09;…...

ArcGIS pro中的回归分析浅析(加更)关于广义线性回归工具的补充内容

在回归分析浅析中篇的文章中&#xff0c; 有人问了一个问题&#xff1a; 案例里的calls数据貌似离散&#xff0c;更符合泊松模型&#xff0c;为啥不采用泊松而采用高斯呢&#xff1f; 确实&#xff0c;在中篇中写道&#xff1a; 在这个例子中我们为了更好地解释变量&#x…...

mybatis-plus 实现分页查询步骤

MyBatis-Plus 是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。它提供了代码生成器、条件构造器、分页插件等多种功能&#xff0c;其中分页查询是一个常用的功能。 以下是如何在 MyBatis-Plus 中实现分页查询…...

Vue开发中常见优化手段总结

Tree Shaking or Trunk 动态引入&#xff08;Dynamic Imports&#xff09; 动态引入是指在代码执行过程中&#xff0c;根据需要动态加载模块&#xff0c;而不是在应用启动时一次性加载所有模块。这可以通过JavaScript的import()函数实现&#xff0c;它返回一个Promise对象&…...

IDEA无法创建java8、11项目创建出的pom.xml为空

主要是由于Spring3.X版本不支持JDK8&#xff0c;JDK11&#xff0c;最低支持JDK17 解决的话要不就换成JDK17以上的版本&#xff0c;但是不太现实 另外可以参考以下方式解决 修改spring初始化服务器地址为阿里云的 https://start.aliyun.com/...

TCP/IP网络编程-C++(上)

TCP/IP网络编程-C &#xff08;上&#xff09; 一、基于TCP的服务端/客户端1、server端代码2、client端代码3、socket() 函数3.1、函数原型3.2、参数解析3.2.1、协议族&#xff08;domain参数&#xff09;3.2.2、套接字类型&#xff08;type参数&#xff09;3.2.3、最终使用的协…...

在线绘制Nature Communication同款双色、四色火山图,突出感兴趣的基因

导读&#xff1a;火山图通常使用三种颜色分别表示显著上调&#xff0c;显著下调和不显著。通过为特定的数据点添加另一种颜色&#xff0c;可以创建双色或四色火山图&#xff0c;从而更直观地突出感兴趣的数据点。 《Nature Communication》文章“Molecular and functional land…...

ctfshow pwn wp

文章目录 Test_your_ncpwn-0pwn1pwn2pwn3pwn4 前置基础pwn5pwn6pwn7pwn8pwn9pwn10pwn11pwn12pwn13&#xff1a;gcc编译执行C语言代码pwn14&#xff1a;gcc编译执行C语言代码pwn15&#xff1a;nasm编译asm&#xff0c;ld链接为可执行文件pwn16&#xff1a;gcc编译汇编文件.s为可…...

【数据结构实战篇】用C语言实现你的私有队列

&#x1f3dd;️专栏&#xff1a;【数据结构实战篇】 &#x1f305;主页&#xff1a;f狐o狸x 在前面的文章中我们用C语言实现了栈的数据结构&#xff0c;本期内容我们将实现队列的数据结构 一、队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端…...

数据结构 (11)串的基本概念

一、串的定义 1.串是由一个或者多个字符组成的有限序列&#xff0c;一般记为&#xff1a;sa1a2…an&#xff08;n≥0&#xff09;。其中&#xff0c;s是串的名称&#xff0c;用单括号括起来的字符序列是串的值&#xff1b;ai&#xff08;1≤i≤n&#xff09;可以是字母、数字或…...

快速高效求素数|质数的方法—Java(模板)

判断素数|质数方法时间效率:线性筛法>埃氏筛法>试除法 在写算法题的时候&#xff0c;各种各样跟素数有关的题目非常常见&#xff0c;本文列出了三种常见的判断素数的方法 三种求素数方法的优缺点 一、试除法 试除法的基本思想是&#xff1a;判断一个数 x 是否为素数&…...

探秘嵌入式位运算:基础与高级技巧

目录 一、位运算基础知识 1.1. 位运算符 1.1.1. 与运算&#xff08;&&#xff09; 1.1.2. 或运算&#xff08;|&#xff09; 1.1.3. 异或运算&#xff08;^&#xff09; 1.1.4. 取反运算&#xff08;~&#xff09; 1.1.5. 双重按位取反运算符&#xff08;~~&#xf…...

iOS 17.4 Not Installed

0x00 系统警告 没有安装 17.4 的模拟器&#xff0c;任何操作都无法进行&#xff01; 点击 OK 去下载&#xff0c;完成之后&#xff0c;依旧是原样&#xff01; 0x01 解决办法 1、先去官网下载对应的模拟器&#xff1a; https://developer.apple.com/download/all/?q17.4 …...

RestTemplate 使用教程

RestTemplate 是 Spring 框架提供的一种用于执行HTTP请求的同步客户端。它简化了与HTTP服务器的交互&#xff0c;并支持RESTful Web服务。 1. 添加依赖 首先&#xff0c;确保你的项目中包含了Spring Web的支持。如果你使用的是Maven&#xff0c;在pom.xml文件中添加如下依赖&…...

windows下安装wsl的ubuntu,同时配置深度学习环境

写在前面&#xff0c;本次文章只是个人学习记录&#xff0c;不具备教程的作用。个别信息是网上的&#xff0c;我会标注&#xff0c;个人是gpt生成的 安装wsl 直接看这个就行&#xff1b;可以不用备份软件源。 https://blog.csdn.net/weixin_44301630/article/details/1223900…...

【贪心算法第五弹——300.最长递增子序列】

目录 1.题目解析 题目来源 测试用例 2.算法原理 3.实战代码 代码解析 注意本题还有一种动态规划的解决方法&#xff0c;贪心的方法就是从动态规划的方法总结而来&#xff0c;各位可以移步博主的另一篇博客先了解一下&#xff1a;动态规划-子序列问题——300.长递增子序列…...

【数据分析】基于GEE解析2000-2020年武汉市FVC时空变化特征

武汉市FVC时空变化特征解析 1. 写在前面2. 2000~2020年武汉市FVC时空变化特征解析2.1. 数据获取与预处理2.2. 辐射定标和大气校正2.3. 云层和云影去除2.4. FVC计算2.5. 时空分析2.6. 代码1. 写在前面 🌍✨在应对全球气候变化和环境监测的挑战中,植被盖度(Fraction Vegetati…...

springboot实战(19)(条件分页查询、PageHelper、MYBATIS动态SQL、mapper映射配置文件、自定义类封装分页查询数据集)

引言&#xff1a; 该类博客的学习是基于b站黑马视频springbootvue视频学习&#xff01;具体围绕项目——"大事件"进行实战学习。 目录 一、功能介绍&#xff08;需求&#xff09;。 1、文章列表功能基本介绍。 2、条件分页查询功能与注意。 3、前端页面效果。&#x…...

Mongo数据库 --- Mongo Pipeline

Mongo数据库 --- Mongo Pipeline 什么是Mongo PipelineMongo Pipeline常用的几个StageExplanation with example:MongoDB $matchMongoDB $projectMongoDB $groupMongoDB $unwindMongoDB $countMongoDB $addFields Some Query Examples在C#中使用Aggreagtion Pipeline**方法一: …...

Docker部署mysql:8.0.31+dbsyncer

Docker部署mysql8.0.31 创建本地mysql配置文件 mkdir -p /opt/mysql/log mkdir -p /opt/mysql/data mkdir -p /opt/mysql/conf cd /opt/mysql/conf touch my.config [mysql] #设置mysql客户端默认字符集 default-character-setUTF8MB4 [mysqld] #设置3306端口 port33…...

银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法

银河麒麟桌面系统——桌面鼠标变成x&#xff0c;窗口无关闭按钮的解决办法 1、支持环境2、详细操作说明步骤1&#xff1a;用root账户登录电脑步骤2&#xff1a;导航到kylin-wm-chooser目录步骤3&#xff1a;编辑default.conf文件步骤4&#xff1a;重启电脑 3、结语 &#x1f49…...

【微服务】 Eureka和Ribbon

一、Eureka 服务调用出现的问题&#xff1a;在远程调用另一个服务时&#xff0c;我们采用的解决办法是发送一次http请求&#xff0c;每次环境的变更会产生新的地址&#xff0c;所以采用硬编码会出现很多麻烦&#xff0c;并且为了应对并发问题&#xff0c;采用分布式部署&#…...

C++设计模式(工厂模式)

一、介绍 1.动机 在软件系统中&#xff0c;经常面临着创建对象的工作&#xff0c;这些对象有可能是一系列相互依赖的对象&#xff1b;由于需求的变化&#xff0c;需要创建的对象的具体类型经常变化&#xff0c;同时也可能会有更多系列的对象需要被创建。 如何应对这种变化&a…...

nodejs第三方库sharp对图片的操作生成新图片、压缩、添加文字水印及图片水印等

Sharp是一个基于libvips的高性能Node.js图像处理库&#xff0c;它提供了广泛的功能&#xff0c;包括调整大小、裁剪、旋转、格式转换等。Sharp可以处理多种图像格式&#xff0c;并且能够高效地转换图像格式。 相关说明及用法看&#xff1a;https://sharp.nodejs.cn/ 安装&#…...