JVM学习笔记---垃圾收集

3.1 垃圾收集(Garbage Collection)关注的问题

  • 哪些内存需要回收?
  • 什么时候回收?
  • 如何回收?

 程序计数器、虚拟机栈、本地方法栈三个区域随线程共存亡,内存的分配和回收具备确定性,所以回收比较方便

 Java堆和方法区则不一样,只有在程序处于运行期间才知道哪些对象会创建,所以这部分内存的创建和回收都是动态的

3.2 对象存活判断算法

3.2.1 引用计数算法

 给对象添加一个引用计数器,每当有地方引用他时,计数器加一,引用失效时。计数器减一,任何时刻计算器为0的对象是不可引用的

 缺点:无法解决对象之间相互循环引用的问题

3.2.2 可达性算法分析(Rechbility Analysis)

 以GC Roots 对象为起点,走过的路径为引用链(Reference Chain) 当一个对象不可达GC Roots 时(即从GC到这个对象不可达时),证明此对象不可用

 可以作为GC Root的对象:

  • 虚拟机栈(栈帧中变量表)中引用的对象 局部变量表的对象
  • 方法区中类静态属性应用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(即Native方法)引用的对象

可达性分析算法

3.2.3 再谈引用

 JDK1.2后将引用分成了四种

  1. 强引用(Strong Reference) 类似于 Objcet o=new Objcet()只要强引用还在,GC就不会回收
  2. **软引用(Soft Renference)**有用但非必需的对象,将要发生内存溢出之前,就会回收这些对象,如果这次还没有回收到足够的内存才会报内存溢出异常
  3. **弱引用(Weak Renference)**非必须对象,当GC工作时,无论内存是否足够,都会回收
  4. **虚引用(Phantom Renference)**幽灵引用/幻影引用 ,虚引用对对象及其生存周期无影响,唯一目的是在这个对象被垃圾收集的时候收到一个通知

3.2.4 生存还是死亡

 即使在可达性分析中不可达的对象也不是非死不可的**,要宣告一个对象的死亡,至少需要经历两次标记过程**

 当一个对象被发现没有与GC Roots相连的引用链的时候,将被第一次标记而且进行一次筛选,筛选该对象有没有必要执行finalize()方法

  • 如果该对象没有覆盖finalize()方法或者finalize()方法已被虚拟机调用过,则没有必要执行
  • 如果被判定为有必要执行,那么这个对象会放置在一个F-Queue的队列中,并稍后在一个由虚拟机自动建立的、低优先级的Finalizer线程去执行,因为低优先级,所以不承诺等待他的运行结果,避免finalize()方法执行缓慢发生死循环等状态

 故而,finalize()方法是对象逃脱死亡命运的最后一次机会,只要在finalize()方法中和GC Roots的引用链相连就可以逃脱死亡的命运,因为稍后GC将对F-Queue的队列进行第二次小规模标记,如果被标记两次,那么死亡宣告

finalize()方法只会被执行一次,下次会直接被回收

3.2.5 回收方法区

 HotSpot虚拟机中永久代的垃圾回收主要回收两部分内容

  • 废弃常量

    以字符串"abc"为例,如果没有任何String对象引用常量池中的"abc",也没有其他地方引用这个字面量,如果此时发生内存回收且必要的话,那么这个"abc"就会被清理出常量池

  • 无用的类

    类需要满足3个条件才算无用类

    • 该类的所有实例都已被回收,即堆内存中不存在该类的任何实例
    • 加载该类的ClassLoader已被回收
    • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

    无用类不是必然被回收,是否对类进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class 以及-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类加载和卸载信息,其中-verbose:class 和 -XX:+TraceClassLoading可以在Product版本的虚拟机中使用,-XX:+TraceClassUnLoading参数需要FastDebug版的虚拟机支持

    在大量使用反射、动态代理、GCLib等ByteCode框架、动态生成JSP以及OSGI这类频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出

3.3 垃圾收集算法

3.3.1 标记-清除算法(Mark-Sweep)

 适用于:老年代

 思想:

  • 标记阶段:首先标记处所有需要回收的对象
  • 清除阶段:在标记完成后统一回收所有被标记的对象

 缺点:

  • 效率问题:标记和清除效率都不高
  • 空间问题:标记清除后会产生大量不连续的内存碎片,会导致在需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次GC
    Mark-Sweep

3.3.2 标记-整理算法(Mark-Compact)

 适用于:老年代

 思想:标记过程与Mark-Sweep一样,标记后会将所有存活的对象都向一段移动,然后直接请里掉边界以外的内存

Mark-Compact

3.3.3复制算法

 适用于:新生代

 思想:将内存划分为两块,每次只是用一块,当这一块用完时,将还存活的对象复制到另一块,然后对整块半区进行回收

 现在商业虚拟机大部分都采用这种算法,并将新生代划分为1块Eden和2块Survivor(一块叫from,一块叫to),Eden和Survivor的大小为8:1。

对象只会存在于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区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中

​ —JVM新生代老年代

缺点:可使用内存变小
Copying

3.3.4 分代收集算法(Generational Collection)

 思想:将java堆分为新生代和老年代,根据各个年代的特点采用最合适的收集算法

  • 新生代:大量对象回收,少量对象存活,选择复制算法
  • 老年代:对象存活率高,选择标记-清除或标记-整理算法

当前的商业虚拟机都采用分代收集

3.4 垃圾收集器

3.4.1 Serial 收集器

  • 最基本、发展最久的收集器,JDk1.3.1之前是虚拟机新生代收集的唯一选择
  • 单线程收集器
  • 工作时会发生STW(Stop The World)
  • 到目前为止仍然是虚拟机运行在Client模式下的默认新生代收集器

3.4.2 ParNew 收集器

  • 是 Serial 的多线程版本(新生代收集器)
  • 是运行在Server模式下的虚拟机中首选的新生代收集器
  • 默认开启的收集线程数与CPU数量相同,可以通过-XX:ParallelGCThreads设置线程数

3.4.3 Parallel Scavenge 收集器

  • 新生代收集器(复制算法)
  • 多线程工作
  • 其目标是达到一个可控制的吞吐量(吞吐量:CPU用于运行用户代码的时间与CPU总消耗时间的比值),提高吞吐量可以高效率地利用CPU时间
    • 吞吐量 = 运行用户代码时间 /(运行用户代码时间+ 垃圾收集时间)
    • 通过两个参数精确控制吞吐量
      • -XX:MaxGCPauseMillis 最大垃圾收集停顿时间
      • -XX:GCTimeRatio 直接设置吞吐量大小,参数范围(0-100)默认为99
  • 适合在后台运算而不需要太多交互的任务场景
  • -XX:UseAdaptiveSizePolicy 开关参数,打开该参数后虚拟机会根据当前系统的运行情况,动态调整其他参数以提供最适合的停顿时间或最大的吞吐量,这种调节方式被称为GC自适应的调节策略

3.4.4 Serial Old 收集器

  • Serial 的老年代版本,单线程,使用标记-整理算法
  • 适用于Client模式下的虚拟机

3.4.5 Parallel Old 收集器

  • Parallel Scavenge的老年代版本,多线程,使用标记-整理算法

3.4.6 CMS 收集器

  • CMS(Concurrent Mark Sweep)以获取最短回收停顿时间为目标的收集器

  • 使用标记-清除算法,整个过程分为四步

    • 初始标记(CMS initial mark)

      标记一下GC Root能直接关联到的对象

    • 并发标记(CMS concurrent mark)

      进行GC Root Tracing(即标记GC Root路线上所有对象)

    • 重新标记(CMS remark)

      修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录

    • 并发清除(CMS concurrent sweep)

    初始标记和重新标记仍然需要STW

  • 默认启动的回收线程数是(CPU数量+3)/ 4

  • 当CMS发生"Concurrent Mode Failure"时,老年代的垃圾收集器从CMS退化为Serial Old,所有应用线程被暂停,停顿时间变长。

关于Concurrent Mode Failure的简介

 缺点:

  • CMS无法处理浮动垃圾(伴随程序运行,出现在标记过程之后的垃圾)只能等待下次GC处理

  • 因为使用标记-清除算法,所以会产生内存碎片,当连续内存无法分配大对象时就不得不提前触发一次FullGC

    CMS提供了一个-XX:UseCMSCompactAtFullCollection开关参数(默认开启),用于在CMS顶不住要进行FullGC时开启内存碎片合并整理过程,但停顿时间不得不边长

    还有另一个参数-XX:CMSFullGCsBeforCompaction,这个参数用于设置执行多少次不压缩的FullGC后进行一次带压缩的(默认是0,即每次都进行碎片整理)

3.4.7 G1 收集器

  • Garbage-First收集器是当今收集器技术发展的最前沿成果之一
  • G1是一款面向服务端应用的垃圾收集器
  • 不需要其他收集器配合

 特点:

  • 并行与并发:充分利用多CPU的优势来缩短STW的停顿时间,部分其他收集器原本需要停顿其他线程的GC动作, G1可以通过并发的方式让其他线程继续执行
  • 分代收集
  • 空间整合:不会产生内存碎片
  • 可预测的停顿:能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒

 使用G1收集器是,Java堆的内存布局与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然保留了新生代老年代的概念,但是他们不再是物理隔离的,都是一部分Region(不需要连续)的集合

G1-Heap

 G1回收器执行步骤:

  • 初始标记(Initial Marking)
  • 并发标记(Concurrent Marking)
  • 最终标记(Final Marking)
  • 筛选回收(Live Data Counting and Evacuation)

3.5 内存分配策略

3.5.1 对象优先在Eden分配

 大多数情况下,对象在新生代Eden区中分配,当Eden没有足够空间进行分配时,虚拟机发起一次Minor GC

3.5.2 大对象直接进入老年代

 大对象是指,需要大量连续内存空间的Java对象,例如较长的数组或字符串。虚拟机提供了-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配

3.5.3 长期存活的对象进入老年代

 虚拟机给每个对象定义了一个对象年龄(Age)计数器。对象每熬过一次Minor GC,年龄就增加1岁,当增加到一定程度时(默认15岁),就会被移至老年代,可以通过参数-XX:MaxTenuringThreshold设置这个阈值。

3.5.4 动态对象年龄判定

  虚拟机并不是永远地要求对象年龄达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中,相同年龄所有对象大小的总和大于Survivor空间的一半,那么年龄大于或等于该年龄的对象就可以直接进入老年代

3.5.5 空间分配担保

在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间

  • 如果大于,则此次Minor GC是安全的

  • 如果小于,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。

    如果HandlePromotionFailure=true,那么会继续检查老年代最大可用连续空间是否大于历次晋升到老年代的对象的平均大小,如果大于,则尝试进行一次Minor GC,但这次Minor GC依然是有风险的;如果小于或者HandlePromotionFailure=false,则改为进行一次Full GC。

内容概要:本文档详细介绍了基于直驱永磁同步发电机(PMSG)的1.5MW风力发电系统在Simulink环境下的建模与仿真全过程,涵盖了风力机空气动力学模型、PMSG电磁特性建模、不可控整流与逆变电路、直流环节、空间矢量脉宽调制(SVPWM)技术以及核心控制策略的设计。重点实现了最大功率点跟踪(MPPT)控制以提升风能捕获效率,并构建了电压外环与电流内环协同工作的双闭环控制系统,通过仿真验证了系统在不同风速条件下稳定运行的能力及动态响应性能。; 适合人群:适用于具备电力系统、电机控制理论基础及Simulink仿真操作经验的研究生、科研人员和从事新能源发电系统开发的工程技术人员;特别适合正在进行风电系统建模、控制算法研究或完成相关毕业设计的专业人士。; 使用场景及目标:①深入理解直驱式PMSG风力发电系统的整体架构与工作机理;②掌握从物理部件建模到控制策略实现的完整Simulink仿真流程;③学习并复现MPPT控制、双闭环控制等关键技术方案;④为后续开展低电压穿越、并网稳定性分析、故障诊断等高级课题提供可靠的仿真平台支撑。; 阅读建议:建议结合Matlab/Simulink软件动手实践,逐模块搭建模型,重点关注各控制环节的参数设计与调试方法,同时可参照文中提供的其他风电相关资源进行拓展学习与对比分析。
已经博主授权,源码转载自 https://pan.quark.cn/s/868afdd63918 在信息技术领域中,前端开发构成了Web应用程序构建的关键环节,而登录注册页面则是用户与网站进行互动的起始界面。"150款web登录注册页面模板(附带效果图+源码)"这一资源为前端工程师们提供了一系列预先设计的界面组件,支持他们迅速构建既美观又实用的登录及注册界面,从而有效缩减开发周期并增强工作效率。 这些模板囊括了多样化的风格和设计潮流,涵盖了扁平化设计、Material Design、渐变色彩、暗黑模式等,能够适应不同项目的特定要求。在设计中强调用户体验,通过科学的布局安排,提升了表单的便捷操作性和可辨识度,并且不忽视视觉层面的吸引力。设计师通常会关注自适应设计,保证页面在多种设备(涵盖手机、平板及桌面电脑)上均能呈现良好的视觉效果。 这些模板均配备了源代码,使得开发者得以深入探究并个性化定制每个构成部分,涉及HTML的页面构造、CSS的样式修饰以及JavaScript的交互逻辑。HTML主要承担着页面基础结构的搭建,CSS用于实现页面美化与布局控制,JavaScript则常用于处理表单验证和交互效果。对于那些精通这三种技术的开发者而言,他们可以根据个人需求对模板进行功能扩展和样式调整。 在实际部署时,登录注册页面通常需要集成基础的输入项,例如用户名、密码、电子邮箱等,并且必须重视安全性考量,诸如密码强度指引、验证码系统等。除此之外,为了优化用户体验,还可能集成记住密码、自动填充、社交平台登录(例如微信、QQ、微博)等功能。 在开发阶段,前端工程师还需关注Web标准和无障碍访问(WCAG)规范,确保页面的通用友好性,这包括视障、听障或其他有特殊需求的用户群体。具体措施涉及标...
源码直接下载地址: https://pan.quark.cn/s/9af8b9f95652 ### Multisim模型的导入和使用 ### 一、引言 随着电子设计自动化(EDA)工具的进步,Multisim已经成为电子工程师进行电路仿真、分析和设计的关键工具之一。借助Multisim,工程师们能够便捷地构建电路模型,并对电路进行仿真验证。本文将系统阐述如何在Multisim中导入并运用芯片仿真模型,这对于提升电子产品的研发效能具有显著价值。 ### 二、Multisim中构建新元器件 构建新元器件是Multisim中的核心功能,特别是对于那些需要特定模型或无法从Multisim库中直接获取的元器件来说更为关键。以下为构建新元器件的具体流程: ##### 步骤1:录入元器件信息 在Multisim中启动“Component Wizard”,即元器件向导,开始创建新的元器件。首先需要录入元器件的基本资料,包括型号、主要功能、类型等。这些资料将有助于用户更高效地管理和检索元器件。 ##### 步骤2:录入封装信息 接下来需要设定元器件的封装信息。在这一环节中,用户需要依据实际芯片的封装规格来选择适宜的引脚数量。同时,还需明确是构建单一部件元器件还是复合部件元器件。如果是复合部件元器件,则必须确保引脚数量与符号中使用的引脚数量保持一致。 ##### 步骤3:录入符号信息 在此步骤中,用户可以编辑元器件在仿真过程中的显示符号。编辑符号可以通过三种途径进行:直接编辑、从数据库中复制现有符号或复制当前符号以备将来使用。编辑符号时应注重其在电路图中的可辨识度和清晰度。 ##### 步骤4:设定管脚参数 在该步骤中,用户需要参照数据手册上的管脚顺序为每个管脚命名,并选择恰当的类型。...
代码转载自:https://pan.quark.cn/s/7b1a6710052c Vivado 2018.2 与 ModelSim 的协同仿真操作 Vivado 2018.2 是由 Xilinx 公司开发的一款用于 FPGA 设计的工具,它包含了丰富的设计和仿真功能。然而,在实际应用过程中,用户可能会遇到其自带的仿真工具运行效率不高的问题。为了提升仿真效率并简化设计验证流程,可以考虑采用第三方仿真工具 ModelSim。ModelSim 是一款性能卓越且市场应用广泛的仿真软件,接下来的内容将详细阐述如何实现 Vivado 2018.2 与 ModelSim 的联合使用。 配置 ModelSim 的安装路径 在使用 Vivado 2018.2 时,首先需要配置 ModelSim 的安装位置。用户可以通过点击 Vivado 菜单中的“Tools”——>“Settings...”选项,然后在弹出的设置界面中,选择“Tool Settings”下的“3rd Party Simulators”选项卡。在“Install Paths”区域,找到“ModelSim”条目,并在此输入或选择 ModelSim 的具体安装路径。 执行器件库编译操作 在 ModelSim 的安装目录下,创建一个名为 xilinx_lib 的子文件夹。随后,在 Vivado 菜单中通过“Tools”——>“Compile Simulation Libraries...”选项启动器件库编译流程,并设定相应的编译参数。在打开的对话框里,将仿真工具选择为“ModelSim Simulator”,保持语言和库的默认设置不变,同时指定编译器件库的存放位置和 ModelSim 可执行文件的路径。 ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值