首页 > 其他分享 >JVM-垃圾回收

JVM-垃圾回收

时间:2023-06-01 09:59:01浏览次数:31  
标签:对象 引用 回收 gc 内存 JVM 垃圾

1.如何判断对象可以回收

1.1.引用计数法

定义:给对象添加一个引用计数器,每当有一个地方引用它,计数器值就加一;相反的,当引用失效的时候,计数器值就减一;任何时刻计数器为0的对象就是不可能再被使用的。
弊端:可能存在无效的循环引用

现在主流的Java虚拟机里并没有选用引用计数算法来管理内存,最主要的原因就是它很难解决对象之间相互循环引用的问题

1.2.可达性分析算法

  • Java虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
  • 扫描堆中的对象,看是否能够沿着GC Root对象为起点的引用链找到该对象,找不到,表示可以回收
  • 哪些对象可以作为GC Root?
    • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
    • 方法区中类静态属性引用的对象。
    • 方法区中常量引用的对象。
    • 本地方法栈中JNI(即一般说的Native方法)引用的对象。

1.3.四种引用

  1. 强引用
  • 只有所有GX Roots对象都不通过【强引用】引用该对象,该对象才能被垃圾回收
  1. 软引用(SoftReference)
  • 仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次触发垃圾回收,回收软引用对象
  • 可以配合引用队列来释放软引用自身
  1. 弱引用(WeakReference)
  • 仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
  • 可以配合引用队列来释放弱引用自身
  1. 虚引用(PhantomReference)
  • 必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会将虚引用入队,由Reference Handler线程调用虚引用相关方法释放直接内存
  1. 终结器引用(FinalReference)
  • 无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize方法,第二次GC时才能回收被引用对象

2.垃圾回收算法

2.1.标记清除

定义:Mark Sweep

  • 速度较快
  • 会造成内存碎片

2.2.标记整理

定义:Mark Compact

  • 速度慢
  • 没有内存碎片

2.3.复制

定义:Copy

  • 不会有内存碎片
  • 需要占用双倍内存空间

3.分代垃圾回收

  • 对象首先分配在伊甸园区域
  • 新生代空间不足时,触发minor gc,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄加1并且交换from to
  • minor gc会引发stop the world,暂停其它用户的线程,等来及回收结束后,用户线程才恢复运行
  • 当对象寿命超过阈值,会晋升至老年代,最大寿命是15(4bit)
  • 当老年代空间不足,会先尝试触发minor gc,如果之后空间仍不足,那么触发full gc,STW的时间更长

3.1相关JVM参数

4.垃圾回收器

  1. 串行
  • 单线程
  • 堆内存较小,适合个人电脑
  1. 吞吐量优先
  • 多线程
  • 堆内存较大,多核cpu
  • 让单位时间内STW的时间最短
  1. 响应时间优先
  • 多线程
  • 堆内存较大,多核cpu
  • 尽可能让单次STW的时间最短

4.1.串行

4.2.吞吐量优先

4.3.响应时间优先

4.4.G1

定义:Garbage First
适用场景

  • 同时注重吞吐量(Throughput)和低延迟(Low latency),默认的暂停目标是200ms
  • 超大堆内存,会将堆划分为多个大小相等的Region
  • 整体上是标记+整理算法,两个区域之间是复制算法

相关JVM参数
-XX:+UseG1GC
-XX:G1HeapRegionSize=size
-XX:MaxGCPauseMillis=time

  1. G1垃圾回收阶段

  2. Young Collection

  • 会STW
  1. Young Collection + CM
  • 在Young GC时会进行GC Root的初始标记
  • 老年代占用堆空间比例达到阈值时,进行并发标记(不会STW),由下面的参数决定
    -XX:InitiatingHeapOccupancyPercent=percent(默认45%)
  1. Mixed Collection
    会对E、S、O进行全面垃圾回收
  • 最终标记(Remark)会STW
  • 拷贝存活(Evacuation)会STW

-XX:MaxGCPauseMillis=ms

  1. Full GC
  • SerialGC
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足发生的垃圾收集-full gc
  • ParallelGC
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足发生的垃圾收集-full gc
  • CMS
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足
  • G1
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足(垃圾回收速度低于产生速度时,并发失败,退化为单线程SerialGC串行执行)
  1. Young Collection跨代引用
  • 新生代回收的跨代引用(老年代引用新生代)问题

  • 卡表与Remembered Set

  • 在引用变更时通过post -write barrier + dirty card queue

  • concurrent refinement threads更新Remembered Set

  1. Remark
  • pre-write barrier + satb_mark_queue
  1. JDK 8u20字符串去重
  • 优点:节省大量内存
  • 缺点:略微多占用了cpu时间,新生代回收时间略微增加

-XX:+UseStringDeduplication

  • 将所有新分配的字符串放入一个队列
  • 当新生代回收时,G1并发检查是否有字符串去重
  • 如果它们的值一样,让它们医用同一个char[]
  • 注意,与String.intern()不一样
    • String.intern()关注的是字符串对象
    • 而字符串去重关注的是char[]
    • 在JVM内部,使用了不同的字符串表

标签:对象,引用,回收,gc,内存,JVM,垃圾
From: https://www.cnblogs.com/hss945/p/17392572.html

相关文章

  • JVM吊打面试官专属秘籍
    01优秀的Java开发者大家都是有经验的Java开发人员,想想为何要学习JVM?[面试?调优?装逼?]不管出于何种原因,总之你得先学好。那怎么学好呢?因为目前课堂中有大学生和工作几年的,也就是每个人对于JVM的了解可能不一样,这就要考虑到怎么切入既然大家都学习过Java,那不妨就从Java开始聊起,......
  • 使用神经网络-垃圾邮件检测-LSTM或者CNN(一维卷积)效果都不错【代码有问题,pass】
     fromsklearn.feature_extraction.textimportCountVectorizerimportosfromsklearn.naive_bayesimportGaussianNBfromsklearn.model_selectionimporttrain_test_splitfromsklearnimportmetricsimportmatplotlib.pyplotaspltimportnumpyasnpfromskle......
  • 获取百度回收网址
    importrandomimporttimefromseleniumimportwebdriverimportrequestsfromlxmlimportetreefromselenium.webdriver.common.byimportBydefrequest_zy(url):response=requests.get(url=url)returnresponse.urldriver=webdriver.Chrome()u......
  • 2.6. Java内存管理与垃圾回收
    2.6.1.Java内存模型在Java中,内存被划分为以下几个区域:堆(Heap):存储对象实例和数组,是垃圾回收的主要区域。栈(Stack):存储局部变量和方法调用。每个线程有自己的栈。方法区(MethodArea):存储类信息,如类的结构、方法、字段等。本地方法栈(NativeMethodStack):存储本地方法(如JNI)的调用......
  • JVM运行时的数据区 (内存溢出实例)
    一、概述运行时数据区是jvm运行时的内存布局,类装载到内存后存放的位置,为执行引擎提供所需指令和数据。运行时数据区包括:堆、栈、方法区、本地方法栈、pc计数器。接下来会详细介绍各个部分,并介绍直接内存访问和方法区中的常量池,另外对于每个区域可能发生的内存异常用demo做讲解。二......
  • JVM 例子,理解
     一个线程一个栈,栈为线程私有。图中只有一个main线程。某方法返回时,它对应的栈帧也会释放掉。方法区进行类加载,类的字节码中有代码code所有对象都在堆进行分配 main线程的时间片(内核分配的)用完了, 上下文切换,cpu执行t1,要把main线程的栈帧都保存下来......
  • JVM垃圾收集算法
    JVM垃圾收集算法当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”(GenerationalCollection)的理论进行设计,分代收集名为理论,实质是一套符合大多数程序运行实际情况的经验法则,分代收集理论建立在两个分代假说之上:弱分代假说(WeakGenerationalHypothesis):绝大多数对象都是朝生......
  • JVM垃圾回收机制
    判断一个对象是否存活的方法:(1)引用计数法:给每个对象设置一个引用计数器,对象被引用时就+1,引用失效时就-1,当对象的引用为0时,该对象就被视为垃圾对象,等待垃圾回收。但是该方法不能解决循环引用问题。例如:A引用B,B应用A。现在的虚拟机一般不用这种方法。(2)可达性分析法:沿着GCRoots对象......
  • 2023-05-26:golang关于垃圾回收和析构函数的选择题,多数人会选错。
    2023-05-26:golang关于垃圾回收和析构的选择题,代码如下:packagemainimport( "fmt" "runtime" "time")typeListNodestruct{ Valint Next*ListNode}funcmain0(){ a:=&ListNode{Val:1} b:=&ListNode{Val:2} runtime.SetFi......
  • JVM常量池
    常量池:可以看作是一张表,虚拟机指令根据常量表找到要执行的类名、方法名、参数类型、字面量等信息。查看字节码结构的指令:javap-vxxx.class。运行时常量池:当类被加载,会把该类的常量池信息放入运行时常量池中,并把里面的符号地址变为真实地址。......