垃圾回收

垃圾Java对象的判断-可达性分析算法

  • 从一系列GCRoots作为起始节点,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),没有在链上的对象就是需要回收的对象。

  • 固定可作为GC Roots的对象

    • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
    • 在方法区中类静态属性引用的对象,如Java类的引用类型静态变量。
    • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
    • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
    • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
    • 所有被同步锁(synchronized关键字)持有的对象。
    • 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
    • 根据用户所选用的垃圾收集器以及当前回收的内存区域不同,还可以有其他对象“临时性”地加入。
  • 对象需要经过2次标记才能真正被回收。

回收方法区

  • 主要回收废弃的常量和不再使用的类型。

    • 如一个字符串“FA♂Q”曾经进入的常量池,现在没有任何字符串对象引用它,就被系统清理出常量池。
    • 常量池中其他类(接口)、方法、字段的符号引用也与此类似。
    • 要判定一个类型是否属于“不再被使用的类”的条件,需要同时满足下面三条。满足后只是被允许回收,不是一定会回收。还和虚拟机参数设置有关。
      • 该类所有的实例都已经被回收。
      • 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的。
      • 该类对应的java.lang.Class对象没有在任何地方被引用。
    • 在大量使用反射、动态代理、CGLib等字节码框架,动态生成JSP以及OSGi这类频繁自定义类加载器的场景中,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力。

垃圾收集算法

分代收集理论

  • 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。

  • 强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡。

  • 跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数。

  • 收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储。

  • 一般至少会把Java堆划分为新生代(Young Generation)和老年代(Old Generation)两个区域。

  • 需在新生代上建立一个全局的数据结构(该结构被称为“记忆集”,Remembered Set),这个结构把老年代划分成若干小块,标识出老年代的哪一块内存会存在跨代引用。

    • 虽然这种方法需要在对象改变引用关系(如将自己或者某个属性赋值)时维护记录数据的正确性,会增加一些运行时的开销,但比起收集时扫描整个老年代来说仍然是划算的。

标记—清除算法

  • 最基础的收集算法,后续的收集算法大多都是以标记—清除算法为基础,对其缺点进行改进而得到的。
  • 缺点1:执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低。
  • 缺点2:内存空间的碎片化。需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

标记—复制算法

  • 将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

优点:对于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存回收,分配内存时也就不用考虑有空间碎片的复杂情况,只要移动堆顶指针,按顺序分配即可。

缺点:空间浪费太多。

  • Appel式回收根据年轻代死的快将空间分为:eden:from:to=8:1:1,每次可用的空间就达到了90%。

    • eden+from用来放对象,需要回收时,就把好对象复制到to区域,坏对象就留着被回收。
    • 逃生门:假如遇到to区域空间不够时,会把年连大的对象直接放到老年区。

标记—整理算法

  • 让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存,更加适用老年代。
  • 移动存活对象并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用程序才能进行,这种停顿被最初的替身使者虚拟机设计者形象的描述为~~”砸哇噜多“~~“Stop The World”
  • 是否移动对象都存在弊端,移动则内存回收时会更复杂,不移动则内存分配时会更复杂。从吞吐量(系统在单位时间内处理请求的数量)来看,移动对象更划算。
  • HotSpot虚拟机里面关注吞吐量的ParallelScavenge收集器是基于标记—整理算法的,而关注延迟的CMS收集器则是基于标记—清除算法的。
  • 还有一种“和稀泥式”解决方案可以不在内存分配和访问上增加太大额外负担,做法是让虚拟机平时多数时间都采用标记—清除算法,时容忍内存碎片的存在,直到内存空间的碎片化程度已经大到影响对象分配时,再采用标记—整理算法收集一次,以获得规整的内存空间。CMS就是用的这种。

HotSpot的算法实现细节

根节点枚举:

  • 并不需要不漏地从方法区等GC Roots开始查找,而是使用一组称为OopMap的数据结构来记录哪些地方存放着对象引用。

安全点(SafePoint)

  • HotSpot没有为每条指令都生成OopMap,只是在安全点记录了这些信息。
  • 以“是否具有让程序长时间执行的特征”为标准进行选定,如方法调用、循环跳转、异常跳转等,只有具有这些功能的指令才会产生安全点。
  • 如何在垃圾收集发生时让所有线程都跑到最近的安全点。
    • **抢先式中断:**系统首先把所有用户线程中断,恢复不在安全点上的线程直到跑到安全点。现在几乎没有虚拟机这样做。
    • **主动式中断:**设置一个标志位,各个线程执行过程中发现中断标志为真时就自己在最近的安全点上主动中断挂起。

安全区域

  • 指能够确保在某一段代码片段之中,引用关系不会发生变化,在这个区域中任意地方开始垃圾收集都是安全的,虚拟机在垃圾收集的时候就不必管在安全区里的线程。
  • 用于处理用户线程处于Sleep状态或者Blocked状态,无法走到安全点。
  • 在垃圾收集过程中需要暂停用户线程的阶段,安全区里的线程无法离开,直到收到可以离开的信号才可以离开。

记忆集

  • 为解决对象跨代引用所带来的问题,垃圾收集器在新生代中建立了叫记忆集的数据结构,用于储存跨代引用的老年代,用以避免把整个老年代加进GC Roots扫描范围。
  • 所有涉及部分区域收集(Partial GC)行为的垃圾收集器,典型的如G1、ZGC和Shenandoah收集器,都会面临相同的问题。
  • 目前最常用的一种记忆集的实现形式是卡表,它定义了记忆集的记录精度、与堆内存的映射关系等(卡精度:每个记录精确到一块内存区域,该区域内有对象含有跨代指针)。
  • 卡表通过写屏障维护,在虚拟机层面对“引用类型字段赋值”这个动作的AOP切面,在引用对象赋值时会产生一个环绕通知,赋值的前后都在写屏障的覆盖范畴内,赋值前的部分的写屏障叫作写前屏障,在赋值后的则叫作写后屏障,HotSpot虚拟机的许多收集器中都有使用到写屏障,但直至G1收集器出现之前,其他收集器都只用到了写后屏障。
  • 卡表在高并发场景下还面临着“伪共享”问题(多线程修改互相独立的变量刚好在同一缓存行里)。
    • 一种简单的解决方案是不采用无条件的写屏障,而是先检查卡表标记,只有当该卡表元素未被标记过时才将其标记为变脏(变脏指存在跨代引用)。
    • -XX:+UseCondCardMark,用来决定是否开启卡表更新的条件判断。

并发的可达性分析

  • 三色标记:把遍历对象图过程中遇到的对象,按照“是否访问过”这个条件标记成以下三种颜色

    • **白色:**表示对象尚未被垃圾收集器访问过。在开始阶段,所有的对象都是白色的,在结束阶段,白色的对象即代表不可达。
    • **黑色:**表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经扫描过。
    • **灰色:**表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用还没有被扫描过。
  • 存在浮动垃圾(芜锁胃,下次再清理就行)与杀错对象(很致命,需要解决)的问题。

  • 产生条件(2者需要同时满足)

    • 赋值器插入了一条或多条从黑色对象到白色对象的新引用
    • 赋值器删除了全部从灰色对象到该白色对象的直接或间接引用
  • 解决方案(实现一种就能解决问题)

    • 增量更新:黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象。
    • 原始快照:当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的白色对象为根,重新扫描一次。

7个经典垃圾收集器

Serial

  • 单线程工作的新生代收集器,它进行垃圾收集时,必须暂停其他所有工作线程。
  • “砸哇噜多Stop The World”这个词语也许听起来很酷,但是用户也许会很难受,影响十分恶劣。
  • Serial看起来很捞,但是还是有用处的,它依然是HotSpot虚拟机运行在客户端模式下的默认新生代收集器。
    • 在内存资源受限的环境,它是所有收集器里额外内存消耗最小的。
    • 对于单核处理器或处理器核心数较少的环境来说,Serial由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。
    • 在用户桌面的应用场景以及近年来流行的部分微服务应用中,分配给虚拟机管理的内存一般来说并不会特别大,收集几十兆甚至一两百兆的新生代(仅仅是指新生代使用的内存,桌面应用甚少超过这个容量),垃圾收集的停顿时间完全可以控制在十几、几十毫秒,最多一百多毫秒以内。

ParNew

  • 实质上是Serial收集器的多线程并行版本。
  • 除了Serial收集器外,目前只有它能与CMS收集器(一款具有划时代意义的并发老年代垃圾收集器)配合工作。
  • ParNew收集器在单核心处理器的环境中绝对不会有比Serial收集器更好的效果,甚至由于存在线程交互的开销。
  • ParNew与CMS曾经是官方推荐服务端收集器组合,在JKD9后就推荐G1了,JDK8G1就已经很成熟,可以用了。

Parallel Scavenge

  • 新生代多线程收集器,诸多特性从表面上看和ParNew非常相似。
  • 目标是达到一个可控制的吞吐量(处理器用于运行用户代码的时间与处理器总消耗时间的比值)。
  • 主要适合在后台运算而不需要太多交互的分析任务。
  • -XX:MaxGCPauseMillis 控制最大垃圾收集停顿时间
    • 允许的值是一个大于0的毫秒数,收集器将尽力保证内存回收花费的时间不超过用户设定值。垃圾收集停顿时间缩短是以牺牲吞吐量和新生代空间为代价换取的。
  • -XX:GCTimeRatio 控制吞吐量大小
    • 值应当是一个大于0小于100的整数,表示垃圾收集时间占总时间的比率
  • -XX:+UseAdaptiveSizePolicy
    • 当这个参数被激活之后,就不需要人工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。

Serial Old

  • Serial收集器的老年版本,单线程,使用标记-整理
  • 服务端模式有2种用途。
    • 一种是在JDK 5以及之前的版本中与Parallel Scavenge收集器搭配使用。
    • 另外一种就是作为CMS收集器发生失败时的后备预案,在并发收集发生Concurrent Mode Failure时使用。

Parallel Old

  • Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程,基于标记-整理算法。
  • 与PS可以成为“吞吐量优先”组合,应用于注重吞吐量或者处理器资源较为稀缺的场合。

CMS

  • 是一种以获取最短回收停顿时间为目标的收集器,关注服务的响应速度,希望系统停顿时间尽可能短,以给用户带来良好的交互体验。
  • 初始标记:是标记一下GCRoots能直接关联到的对象,速度很快。
  • 并发标记:是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行。
  • 重新标记:修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录(三色标记的增量更新),速度较快。
  • 并发清除:清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
  • 缺点
    • CMS收集器对处理器资源非常敏感,并发阶段会导致应用程序变慢,降低总吞吐量

      • 处理器核心数量不足四个时,CMS对用户程序的影响就可能变得很大,可能导致用户程序的执行速度忽然大幅降低。
      • 解决方案 虚拟机提供了一种称为 ”量式并发收集器“的CMS收集器变种,在并发标记、清理的时候让收集器线程、用户线程交替运行,垃圾收集的过程会更长,但对用户程序的影响就会显得较少一些。
    • 由于CMS收集器无法处理“浮动垃圾”,有可能出现“Concurrent Mode Failure”失败。进而导致另一次完全“砸哇噜多”的Full GC的产生。
      • CMS收集器当老年代使用了(JDK5是68%)/(JDK6是92%)的空间后就会被激活(因为是并发的,所以需要留一些空间给用户) 通过 -XX:CMSInitiatingOccupancyFraction 来设置。
      • 要是CMS运行期间预留的内存无法满足程序分配新对象的需要,就会出现一次“并发失败”(Concurrent Mode Failure),此时虚拟机会发动“砸哇噜多”,启动Serial Old来收集垃圾,如果内存空间比较大的话,会停很久,离谱点好像会停好几天。
    • 基于“标记-清除”算法,空间碎片过多时会给大对象分配带来很大麻烦,连续空间不足会频繁FullGC
      • -XX:+UseCMSCompactAtFullCollection**(JDK9废除)** 用于在CMS收集器不得不进行Full GC时开启内存碎片的合并整理过程,但是这个阶段又得卡半天。
      • -XX:CMSFullGCsBeforeCompaction (JDK9废除) 这个参数的作用是要求CMS收集器在执行过若干次(数量由参数值决定)不整理空间的Full GC之后,下一次进入Full GC前会先进行碎片整理。
  • CMS毛病还是挺多的(JDK9已经不推荐使用了,《并发赘婿》《没用的废物》《loser》),JDK有8就不要用ParNew+CMS了吧,G1,永远滴神!(ZGC:抱歉,在下才是)。具体情况还是要具体分析,还是得看压测,总之小内存更适合CMS,大内存适合G1,平衡点通常在6GB至8GB之间。

G1

  • 面向服务端应用的垃圾收集器
  • 面向堆内存任何部分来组成回收集进行回收,哪块内存中回收收益最大就回收哪儿。
  • 是把连续的Java堆划分为多个大小相等的独立区域(Region),每个区域根据需要扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理。
    • Region中还有一类特殊的Humongous区域,专门用来存储大对象(超过Region容量一半的对象)。
    • 每个Region的大小可以通过参数-XX:G1HeapRegionSize设定,取值范围为1MB~32MB,且应为2的N次幂
    • 超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待。
  • 用户可以设定允许的收集停顿时间(-XX:MaxGCPauseMillis指定,默认200毫秒)。
    • G1收集器去跟踪各个Region里面的垃圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间的经验值(经验值指按照以往经验,回收多大的区域,需要多少时间,不是升级的经验值),然后在后台维护一个优先级列表。在给定时间内优先处理回收价值收益最大的那些Region。
  • G1的记忆集在存储结构的本质上是一种哈希表,Key是别的Region的起始地址,Value是一个集合,里面存储的元素是卡表的索引号。这种“双向”的卡表结构(卡表是“我指向谁”,这种结构还记录了“谁指向我”),由于每个Region都维护有卡表,因此G1收集器要比其他的传统垃圾收集器有着更高的内存占用负担。根据经验,G1至少要耗费大约相当于Java堆容量10%至20%的额外内存来维持收集器工作。
  • 在并发阶段G1为每一个Region设计了两个名为TAMS的指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象地址都必须要在这两个指针位置以上。G1收集器默认在这个地址以上的对象是被隐式标记过的,即默认它们是存活的,不纳入回收范围。
  • 如果内存回收的速度赶不上内存分配的速度,G1收集器也要被迫冻结用户线程执行,导致Full GC而产生长时间卡住。
  • 运作过程
    • 初始标记:仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象。
    • 并发标记:从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象。扫描完成以后,还要重新处理SATB(原始快照)记录下的在并发时有引用变动的对象。
    • 最终标记:暂停下用户线程,处理并发阶段结束后遗留下来的最后那少量的SATB(原始快照)记录。
    • 筛选回收:负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region构成回收集,然后标记-复制回收。

垃圾收集器的选择依据

  • 程序关注点

    • **吞吐量:**比如数据分析、科学计算类的任务。
    • 响应时间:比如服务型的应用,网购啥的。
    • 内存占用:客户端应用或者嵌入式应用。
  • 运行应用的基础设施如何,譬如硬件规格,处理器的数量,分配内存的大小,选择的操作系统是Linux、Solaris还是Windows

    等。

  • 使用JDK的发行商,版本号。

对象的分配与回收策略

  • 大多数情况下对象优先在Eden分配。当Eden区没有足够空间进行分配时,虚拟机将发起 一次Minor GC。

  • 大对象直接进入老年代(HotSpot虚拟机提供了-XX:PretenureSizeThreshold参数,指定大于该设置值的对象直接在老年代分配,避免在Eden区及两个Survivor区之间来回复制),写程序的时候应注意避免写出“短命的大对象”。

  • 长期存活的对象将进入老年代,对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15,最多也只能为15,因为对象头里放年龄信息的地方只有4位),就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。

  • 动态对象年龄判定,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。换句话说,如果程序员中相同年龄所有对象大小的总和大于上班中程序员数量的一半,年龄大于或等于该年龄的对象就可以直接进入退休代。

  • 空间分配担保,在发生Minor GC之前,虚拟机必须先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那这一次Minor GC可以确保是安全的。如果不成立,则虚拟机会先查看-XX:HandlePromotionFailure参数的设置值是否允许担保失败(Handle Promotion Failure);如果允许,那会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者-XX:HandlePromotionFailure设置不允许冒险,那这时就要改为进行一次Full GC。在JDK 6 Update 24之后-XX:HandlePromotionFailure参数失效,规则变为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小,就会进行Minor GC,否则将进行Full GC。

Java垃圾收集器与内存分配策略详解相关推荐

  1. java eden分配参数,JVM垃圾收集器与内存分配策略,

    垃圾收集器与内存分配策略 对象存活判断 引用计数算法 给对象添加一个计数器,每有一个引用+1,当引用失效-1,若为0则不在被使用. 可达性分析算法 对象是否可到达GC roots 或者说GC root ...

  2. 【深入理解Java虚拟机学习笔记】第三章 垃圾收集器与内存分配策略

    最近想好好复习一下java虚拟机,我想通过深读 [理解Java虚拟机 jvm 高级特性与最佳实践] (作者 周志明) 并且通过写一些博客总结来将该书读薄读透,这里文章内容仅仅是个人阅读后简短总结,加强 ...

  3. java虚拟机读书笔记 第三章 垃圾收集器和内存分配策略

    java虚拟机读书笔记 第三章 垃圾收集器和内存分配策略 GC需要完成的三件事情:哪些内存需要回收.什么时候回收.如何回收 垃圾回收器在对堆进行回收前,首先要确定那些对象存活,哪些对象已经死去,判断的 ...

  4. java内存分配和垃圾回收_深入理解java虚拟机(二)垃圾收集器与内存分配策略...

    垃圾收集器与内存分配策略 垃圾收集,三个步骤 什么时候收集,收集那些,怎么收集 1.收集那些 我们会将一些不使用的对象进行收集,进行回收内存空间,我们怎么知道呢 1.引用计数法 如果这个实例被其他地方 ...

  5. 读书笔记——Java虚拟机垃圾收集器与内存分配策略

    本文章已授权微信公众号郭霖(guolin_blog)转载. 本文章讲解的内容是Java虚拟机垃圾收集器与内存分配策略. 概述 说起垃圾收集(Garbage Collection),也就是GC,大部分人 ...

  6. 《深入理解JAVA虚拟机》学习日志----一、自动内存管理机制(2.垃圾收集器与内存分配策略)

    二.垃圾收集器与内存分配策略 前言:讨论的区域集中在Java堆和方法区中,而其他几个区域的内存分配和回收都具备确定性,所以不需过多考虑回收 的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了. ...

  7. jvm(3)-垃圾收集器与内存分配策略

    [0]README 0.1)本文部分文字转自:深入理解jvm,旨在学习 垃圾收集器与内存分配策略 的基础知识: [1]垃圾回收概述 1)GC(Garbage Collection)需要完成的3件事情: ...

  8. jvm垃圾收集器与内存分配策略

    2019独角兽企业重金招聘Python工程师标准>>> 垃圾收集器与内存分配策略: 以下参考周志明的<<深入理解jvm高级特性与最佳实践>>. 判断对象是否存 ...

  9. 7种垃圾收集器与内存分配策略,看这一篇就够了

    垃圾收集器与内存分配策略-垃圾收集器 (A).图中展示了7种不同分代的收集器: Serial.ParNew.Parallel Scavenge.Serial Old.Parallel Old.CMS. ...

最新文章

  1. how to create view (windows)
  2. Redis(window版本)
  3. 2019年末逆向复习系列之努比亚Cookie生成逆向分析
  4. Sklearn (一) 监督学习
  5. 我是如何学习写一个操作系统(三):操作系统的启动之保护模式
  6. faster rcnn学习之rpn训练全过程
  7. php 顺序结构,顺序存储结构php实现
  8. asp sql 导出 excel_Mysql数据导出到excel基于python
  9. vm虚拟机联网最简单的方式
  10. 获取公司的maven库 和 idea maven 中Projects Settings的Libraries中正常,但是在Maven Projects中Dependencies一直出现红线的解决办法
  11. qml 定义函数_QML类型系统
  12. 继承中父类、子类构造器中的super. 和super()运用
  13. js 编写一道程序题输入长和宽之后点击按钮可弹出长方形面积。
  14. USB组合设备 Interface Association Descriptor (IAD)
  15. Julia: 一行代码可以写出什么优雅?
  16. 短时傅里叶变换原理解
  17. 荣耀MagicBook 2019 Intel版发布:性能新升级 续航长达15小时!
  18. 收付款单提交时分录自动清空
  19. [ kvm ] 学习笔记 1:Linux 操作系统及虚拟化
  20. 将正式数据库中的表与测试库同步

热门文章

  1. 软交所胡才勇获“2014中国软件和信息服务十大领军人物”
  2. Android开发: 分享利用好Kotlin的特点提高开发效率
  3. Java 的几种版本
  4. 怎么修改artifact_《Artifact》怎么修改卡牌描述 修改卡牌描述与游戏UI文字方法分享...
  5. 5分钟教会你在安卓手机上下载liuns系统的ubuntu版本
  6. tensorflow || 滑动平均的理解--tf.train.ExponentialMovingAverage
  7. c语言实现滑动平均_方格网上观测数据的窗口滑动平均处理——C语言
  8. MD5加密之DigestUtils工具类
  9. Explain关键字详解
  10. 苹果M1「徒有其表」?「地表最强」芯只能剪视频引知乎热议