【Java】垃圾回收

2023-11-05

目录

概述:

什么是垃圾(Garbage)?

想要学习GC,首先需要理解为什么需要GC?

Java 垃圾回收机制:

Java自动内存管理的优点:

关于自动内存管理的担忧:

GC 的作用区域:

垃圾回收相关算法(重要):

标记阶段:引用计数器算法和可达性分析算法

标记阶段:引用计数算法

标记阶段:可达性分析算法

可达性分析算法的注意事项

对象的 finalization 机制:

清除阶段:

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

标记-清除算法的缺点:

标记复制算法:

复制算法的优缺点:

标记-压缩算法:

标记-压缩算法的执行流程:

标记-压缩算法与标记-清除算法的比较:

标记-压缩算法的优缺点:

对比三种清除阶段的算法:

分代收集算法:

为什么要使用分代收集算法?

内存溢出(OOM)、内存泄露:



概述:

1、Java 和 C++语言的区别,就在于垃圾收集技术和内存动态分配上,C语言没有垃圾收集技术,需要我们手动的收集。

2、垃圾收集,不是Java语言的伴生产物。早在1960年,第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生。

3、关于垃圾收集有三个经典问题: 

    哪些内存需要回收?

    什么时候回收?

    如何回收?

4、垃圾收集机制是Java的招牌能力,极大地提高了开发效率。如今,垃圾收集几乎成为现代语言的标配。

什么是垃圾(Garbage)?

1、垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾

外文:An object is considered garbage when it can no longer be reached from any pointer in the running program.

2、如果不及时对内存中的垃圾进行清理,这些垃圾对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用。甚至可能导致内存溢出

想要学习GC,首先需要理解为什么需要GC?

1、对于高级语言来说,一个基本认知是如果不进行垃圾回收,内存迟早都会被消耗完,因为不断地分配内存空间而不进行回收,就好像不停地生产生活垃圾而从来不打扫一样。

2、除了释放没用的对象,垃圾回收也可以清除内存里的记录碎片。碎片整理将所占用的堆内存移到堆的一端,以便JVM将整理出的内存分配给新的对象(尤其是一些大的对象)。

3、随着应用程序所应付的业务越来越庞大、复杂,用户越来越多,没有GC就不能保证应用程序的正常进行。而经常造成STW(Stop the World)的GC又跟不上实际的需求,所以才会不断地尝试对GC进行优化。

Java 垃圾回收机制:

Java自动内存管理的优点:

1、自动内存管理无需开发人员手动参与内存的分配与回收,这样降低内存泄漏和内存溢出的风险

2、没有垃圾回收器,java也会和cpp一样,各种悬垂指针,野指针,泄露问题让你头疼不已。

3、自动内存管理机制,将程序员从繁重的内存管理中释放出来,可以更专心地专注于业务开发

关于自动内存管理的担忧:

1、对于Java开发人员而言,自动内存管理就像是一个黑匣子,如果过度依赖于“自动”,那么这将会是一场灾难,最严重的就会弱化Java开发人员在程序出现内存溢出时定位问题和解决问题的能力。

2、了解JVM的自动内存分配和内存回收原理显得非常重要,只有在真正了解JVM是如何管理内存后,我们才能够在遇见OutofMemoryError时,快速地根据错误异常日志定位问题和解决问题。

3、当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就必须对这些“自动化”的技术实施必要的监控和调节。

GC 的作用区域:

1、频繁在新生区收集,很少在养老区收集,几乎不在方法区(永久区/元空间)收集,其中,Java堆是垃圾收集器的工作重点

2、从次数上讲:

    频繁收集Young区

    较少收集Old区

    基本不收集方法区

3、GC主要关注于方法区和堆中的垃圾收集

引用类型才需要垃圾回收,基本数据类型不需要回收。

垃圾回收相关算法(重要):

进行垃圾回收的时候首先要确定哪些是垃圾(判断对象是否可用)?找到垃圾之后怎么清理掉?

分为标记阶段和清除阶段

标记阶段:引用计数器算法和可达性分析算法

标记阶段的目的: 判断对象是否存活
1、在堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。
2、只有被标记为己经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。
3、那么在JVM中究竟是如何标记一个死亡对象呢?简单来说,当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。
4、判断对象存活一般有两种方式:引用计数算法和可达性分析算法。

标记阶段:引用计数算法

1、引用计数算法(Reference Counting)比较简单,对每个对象保存一个整型的引用计数器属性。用于记录对象被引用的情况。
2、对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。
3、优点: 实现简单,垃圾对象便于辨识; 判定效率高,回收没有延迟性。
4、缺点:
     1、它需要单独的字段存储计数器,这样的做法增加了存储 空间的开销
     2、每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了 时间开销。
      3、引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。
循环引用举例:
当p的指针断开的时候,内部的引用形成一个循环,这就是循环引用,从而造成内存泄漏

内存泄露:这个对象不再使用,但是GC没法回收

p指向null,后面三个对象都不再使用了,但是引用计数都不是0,就没法GC回收。

如果让你举内存泄露的例子,最好不要举这个例子,因为Java里面没有使用这个例子,如果举这个要指出是引用计数算法的。

Java中的内存泄露问题_Neon Zhou的博客-CSDN博客_java内存泄漏

标记阶段:可达性分析算法

可达性分析算法:也可以称为根搜索算法、追踪性垃圾收集
在Java中,是通过可达性分析(Reachability Analysis)来判定对象是否存活的。该算法的基本思路就是通过一些被称为 引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。 
相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点, 更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题,防止内存泄漏的发生。
可达性分析算法基本思路:
所谓"GCRoots”根集合就是一组必须活跃的引用,其基本思路如下:
1、可达性分析算法是以根对象集合(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。
2、使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链( Reference Chain
3、如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。
4、在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。
GC Roots可以是哪些元素?所谓GC Roots, 就是一组必须活跃的引用
1、虚拟机栈中引用的对象,比如:各个线程被调用的方法中使用到的参数、局部变量等。
2、静态变量引用的对象,除非类卸载,否则他引用的对象一直存在
3、所有被同步锁synchronized持有的对象(synchronize持有的对象要是被销毁,同步就失效了)

所以如果一个引用(指针),它保存了堆内存里面的对象,那它就是一个Root。

栈、方法区、常量池 结构引用堆空间里面的对象,图里面蓝色的,可达对象。红色不可达,是垃圾。

可达性分析算法的注意事项

如果要使用可达性分析算法来判断内存是否可回收,那么分析工作必须在一个能保障一致性的快照中进行。这点不满足的话分析结果的准确性就无法保证。

这点也是导致GC进行时必须“Stop The World”的一个重要原因。

对象的 finalization 机制:

对象销毁前的回调函数:finalize()

1、Java语言提供了对象终止(finalization)机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。

2、当垃圾回收器发现没有引用指向一个对象,即:垃圾回收此对象之前,总会先调用这个对象的finalize()方法。

3、finalize() 方法允许在子类中被重写,用于在对象被回收时进行资源释放。通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件、套接字和数据库连接等。

// 等待被重写 
protected void finalize() throws Throwable { }

即使重写了这个方法,永远不要主动调用某个对象的finalize()方法应该交给垃圾回收机制调用。

1、在finalize()时可能会导致对象复活。

2、finalize()方法的执行时间是没有保障的,它完全由GC线程决定,极端情况下,若不发生GC,则finalize()方法将没有执行机会。

3、因为优先级比较低,即使主动调用该方法,也不会因此就直接进行回收。

清除阶段:

目前在JVM中比较常见的三种垃圾收集算法是

1、标记清除算法(Mark-Sweep)

2、标记复制算法(Copying)

3、标记压缩算法(Mark-Compact)

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

标记阶段是把所有活动对象(可达对象,reachable)都做上标记的阶段。清除阶段是把那些没有标记的对象,也就是非活动对象回收的阶段。

当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被称为stop the world),然后进行两项工作,第一项则是标记,第二项则是清除。要把用户线程停下来,因为用户线程运行就又会产生垃圾,要保持一致性,就将用户线程先停下来。

标记-清除算法的缺点:

1、标记清除算法的效率不算高 (需要进行遍历)

2、在进行GC的时候,需要停止整个应用程序,用户体验较差

3、这种方式清理出来的空闲内存是不连续的,产生内碎片,需要维护一个空闲列表。

所以现在新的垃圾收集器没有使用这个算法的了,因为产生碎片

标记复制算法:

将活着的 内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收。

没有标记的过程,把可达的对象,直接复制到内存大小一样的另外一个区域中,而且是连续存放, 复制完成后,A区里面的对象就没有用了,下一次从B区复制到A区,这样交换使用。

没有标记的过程,把可达的对象,直接复制到内存大小一样的另外一个区域中,而且是连续存放, 复制完成后,A区里面的对象就没有用了,下一次从B区复制到A区,这样交换使用。

新生代的S0和S1也是使用复制算法。

复制算法的优缺点:

优点

1、没有标记和清除过程,实现简单,运行高效

2、复制过去以后保证空间的连续性,不会出现“碎片”问题。

缺点 :此算法的缺点也是很明显的,就是需要两倍的内存空间。

复制算法的应用场景

即特别适合垃圾对象很多,存活对象很少的场景;例如:Young区的Survivor0和Survivor1区

如果活动对象太多,那么每次就需要复制很多才行,效率就低。老年代大量的对象存活,那么复制的对象将会有很多,效率会很低

在新生代,对常规应用的垃圾回收,一次通常可以回收70% - 99% 的内存空间。回收性价比很高。所以现在的商业虚拟机都是用这种收集算法回收新生代。

标记-压缩算法:

标记-清除-压缩(Mark-Sweep-Compact)算法,是对标记-清除算法的改进

背景:

1、复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的。这种情况在新生代经常发生,但是在老年代,更常见的情况是大部分对象都是存活对象。如果依然使用复制算法,由于存活对象较多,复制的成本也将很高。因此,基于老年代垃圾回收的特性,需要使用其他的算法。

2、标记-清除算法的确可以应用在老年代中,但是该算法不仅执行效率低下,而且在执行完内存回收后还会产生内存碎片,所以JVM的设计者需要在此基础之上进行改进。

标记-压缩(Mark-Compact)算法由此诞生。

标记-压缩算法的执行流程:

1、第一阶段和标记清除算法一样,从根节点开始标记所有被引用对象

2、第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。

标记-压缩算法与标记-清除算法的比较:

1、标记-压缩算法的最终效果等同于标记-清除算法执行完成后,再进行一次内存碎片整理,因此,也可以把它称为标记-清除-压缩(Mark-Sweep-Compact)算法。

2、二者的本质差异在于标记-清除算法是一种非移动式的回收算法,标记-压缩是移动式的。是否移动回收后的存活对象是一项优缺点并存的风险决策。

3、可以看到,标记的存活对象将会被整理,按照内存地址依次排列,而未被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可,这比维护一个空闲列表显然少了许多开销(标记-清除算法需要空闲列表)。

标记-压缩算法的优缺点:

优点

1、消除了标记-清除算法当中,内存区域分散的缺点,有碎片。

2、消除了复制算法当中,内存减半的高额代价。

缺点

1、从效率上来说,标记-整理算法要低于其他算法,因为有碎片的整理过程

2、移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址

3、移动过程中,需要全程暂停用户应用程序,时间要长一些。即:STW

对比三种清除阶段的算法:

1、效率上来说,复制算法是当之无愧的老大,但是却浪费了太多内存。

2、而为了尽量兼顾上面提到的三个指标,标记-整理算法相对来说更平滑一些,但是效率上不尽如人意,它比复制算法多了一个标记的阶段,比标记-清除多了一个整理内存的阶段。

3、综合我们可以找到,没有最好的算法,只有最合适的算法。

分代收集算法:

为什么要使用分代收集算法?

1、分代收集算法,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。
2、一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点使用不同的回收算法,以提高垃圾回收的效率。
3、在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关:
     比如Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长。
     但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至只用一次即可回收。
分代收集算法的分代依据:
目前几乎所有的GC都采用分代收集算法执行垃圾回收的
在HotSpot中,基于分代的概念,GC所使用的内存回收算法必须结合年轻代和老年代各自的特点。
1、年轻代(Young Gen)
     1、年轻代特点:区域相对老年代较小,对象生命周期短、存活率低,回收频繁。
     2、这种情况 复制算法的回收整理, 速度是最快的。复制算法的效率只和当前存活对象大小有关,因此很适用于年轻代的回收。而复制算法内存利用率不高的问题,通过hotspot中的两个survivor的设计得到缓解。
2、老年代(Tenured Gen)
    老年代特点:区域较大,对象生命周期长、存活率高,回收不及年轻代频繁。
    这种情况存在大量存活率高的对象,复制算法明显变得不合适。一般是由 标记-清除或者是标记-清除与标记-清除-整理的混合实现

内存溢出(OOM)、内存泄露:

内存溢出(OOM)

1、由于GC一直在发展,所有一般情况下,除非应用程序占用的内存增长速度非常快,造成垃圾回收已经跟不上内存消耗的速度,否则不太容易出现OOM的情况。

2、大多数情况下,GC会进行各种年龄段的垃圾回收,实在不行了就放大招,来一次独占式的Full GC操作,这时候会回收大量的内存,供应用程序继续使用。

3、Javadoc中对OutofMemoryError的解释是,没有空闲内存,并且垃圾收集器也无法提供更多内存。

内存溢出(OOM)原因分析:说明Java虚拟机的堆内存不够。

1、大量的内存泄露会导致内存溢出

2、代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)

3、也很有可能就是堆的大小不合理,我们可以通过参数-Xms 、-Xmx来调整。

说明:

1、在抛出OutofMemoryError之前,通常垃圾收集器会被触发,尽其所能去清理出空间。

2、当然,也不是在任何情况下垃圾收集器都会被触发的

     比如,我们去分配一个超大对象,类似一个超大数组超过堆的最大值,JVM可以判断出垃圾收集并不能解决这个问题,所以直接抛出OutofMemoryError。  

内存泄漏(Memory Leak)

1、只有对象不会再被程序用到了,但是GC又不能回收他们的情况,才叫内存泄漏。

2、但实际情况很多时候一些不太好的实践(或疏忽)会导致对象的生命周期变得很长甚至导致OOM,也可以叫做宽泛意义上的“内存泄漏”。

      静态变量和类的生命周期一样。

3、尽管内存泄漏并不会立刻引起程序崩溃,但是一旦发生内存泄漏,程序中的可用内存就会被逐步蚕食,直至耗尽所有内存,最终出现OutofMemory异常,导致程序崩溃。

内存泄露的举例:

左边的图:Java使用可达性分析算法,最上面的数据不可达,就是需要被回收的对象。

右边的图:后期有一些对象不用了,按道理应该断开引用,但是存在一些链没有断开,从而导致没有办法被回收。

单例模式

单例的生命周期和应用程序是一样长的,所以在单例程序中,如果持有对外部对象的引用的话,那么这个外部对象是不能被回收的,则会导致内存泄漏的产生。

一些提供close()的资源未关闭,导致内存泄漏

数据库连接 dataSourse.getConnection(),网络连接socket和io连接必须手动close,否则是不能被回收的。

一个生命周期长的对象引用了一个生命周期短的对象,这个生命周期短的就是可达的,即使不再使用,也不会被GC销毁。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Java】垃圾回收 的相关文章

  • Spring @PostConstruct 依赖于 @Profile

    我想在一个配置类中拥有多个 PostConstruct 带注释的方法 这些方法应该根据 Profile 进行调用 你可以想象这样的代码 Configuration public class SilentaConfiguration priv
  • 从文件中读取文本并将每行中的每个单词存储到单独的变量中

    我有一个包含以下内容的 txt 文件 1 1111 47 2 2222 92 3 3333 81 我想逐行读取并将每个单词存储到不同的变量中 例如 当我读取第一行 1 1111 47 时 我想将第一个单词 1 存储到var 1 1111 进
  • Spring 框架 application.properties 与 logback.xml

    我正在使用 Spring 和 Spring boot 最近 在尝试使用 EhCache 时 我尝试为 EhCache 启用日志记录 在 application properties 中设置日志级别 logging level org spr
  • 在这个 Spring MVC 展示示例中如何使用 @RequestAttribute 和 @ModelAttribute 注释?

    我对 Spring MVC 还很陌生 这段时间我正在学习Spring MVC 展示 https github com spring projects spring mvc showcase可从 STS 仪表板下载示例 我在理解此示例中如何处
  • 使用 Firebase Java API 检索/格式化数据的最佳方式

    我在用着Firebase用于数据存储Android项目 并使用Firebase Java API来处理数据 不过 我不确定我是否尽可能高效地完成此操作 并且我希望获得一些有关检索和格式化数据的最佳实践的建议 我的Firebase存储库看起来
  • 在 Java 中重新抛出异常而不丢失堆栈跟踪

    在 C 中 我可以使用throw 语句重新抛出异常 同时保留堆栈跟踪 try catch Exception e if e is FooException throw Java中有没有类似的东西 不会丢失原始堆栈跟踪 catch Whate
  • Spring Kafka - 为任何主题的分区消耗最后 N 条消息

    我正在尝试读取请求的卡夫卡消息数 对于非事务性消息 我们将从 endoffset N 对于 M 个分区 开始轮询并收集当前偏移量小于每个分区的结束偏移量的消息 对于幂等 事务消息 我们必须考虑事务标记 重复消息 这意味着偏移量将不连续 在这
  • Logback线程池

    我使用 Logback 进行日志记录 我有一个问题 我将 AsyncAppender 与 ConsoleAppender 结合使用 当应用程序启动时 它会创建具有 logback 线程名称的线程池 所有日志记录工作均由 AsyncAppen
  • Eclipse JAVA工具jar不存在

    The archive C Java jdk1 6 0 26 32 lib tools jar which is referenced by the classpath does not exist 这是我运行Tomcat时遇到的错误 清理
  • 用Java截取网页的屏幕截图[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有没有一个免费的工具可以读取给定的网页并截取它的屏幕截图 我使用 VirtualFramebuffer 和 Firefox Binary
  • 如何在Eclipse中制作war文件[重复]

    这个问题在这里已经有答案了 制作war文件的简单方法是什么 当我右键单击 在服务器上运行 时 我的项目正在运行 但我想部署在 tomcat 服务器上 我已经安装了m2clipse但这给了我一个错误 maven是否必须制作war文件 我需要特
  • 规范路径和绝对路径有什么区别? [复制]

    这个问题在这里已经有答案了 可能的重复 Java 中的 getPath getAbsolutePath 和 getCanonicalPath 有什么区别 https stackoverflow com questions 1099300 w
  • JConsole主类

    我正在尝试使用其 Main 类从命令行启动 JConsole 我提取了 jconsole jar 的内容 在 MANIFEST MF 中我可以看到 Main Class sun tools jconsole JConsole 所以我尝试运行
  • 如何使用 Selenium WebDriver 和 Java 滚动特定的 DIV?

    WebDriver 无法识别某些 WebElement WebDriver 无法找到浏览器可见区域中不可见的元素 In order to make the WebElement viewable by WebDriver We need t
  • 有没有办法使用 SauceLabs 的 RemoteWebDriver 禁用 CORS 检查

    问题说明了一切 我正在尝试在 SauceLabs 上执行一些硒测试 该测试加载一个发出跨域请求的网页 我在想是否有一种方法可以通过代码以独立于平台的方式禁用 CORS 使用时Chrome驱动程序 Chrome组合禁用cors questio
  • 是否可以使用“WHERE”子句来选择SQL语句中的所有记录?

    晚上好 我很好奇是否可以在 SQL 语句中创建一个 WHERE 子句来显示所有记录 下面一些解释 随机 SQL 语句 Java JSP示例 正常情况 String SqlStatement SELECT FROM table example
  • android.R.layout.simple_list_item_1是什么?

    在我看到的所有示例中 他们在创建 ArrayAdapter 时仅使用 android R layout simple list item 1 android R layout simple list item 1是什么 它只是一个名为sim
  • CompletableFuture 的多个 thenAccept 块的执行顺序是什么

    所以我有一个返回a的方法CompletableFuture 在返回之前 此方法添加一个块thenAccept这是在之后执行的CompletableFuture完成 此方法的调用者还添加了另一个块thenAccept 显然 这可以通过多个链式
  • 所有语言中特殊字符的 Java 正则表达式

    在我的用户输入字段中 我想允许某些特殊字符 字母和数字的组合 我应该确保正则表达式模式在输入时允许此设置任何语言 基本上我构建的这个正则表达式也应该支持 unicode 表示 如何使用 Java 中的 Pattern 类来实现这一点 这里给
  • Java 中的下载管理器 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要通过 FTP HTTP 从 Java 获取几个大文件 几个演出 有现成的库 java 命令行工具

随机推荐

  • 循环数组有几种方法?

    第一种 普通for循环 for i 0 i
  • H3C交换机SSH配置举例

    注 本文仅供个人学习参考 禁止用作商业用途 因他人转载产生纠纷 本人不承担任何责任 password认证配置举例 1 组网需求 如图 配置Host SSH客户端 与Switch建立本地连接 Host采用SSH协议登录到Switch上 以保证
  • Unity3d--实现太阳系仿真

    一 实验要求 写一个程序 实现一个完整的太阳系 其他星球围绕太阳的转速必须不一样 且不在一个法平面上 二 实验过程 创建如下结构 solar 里包括太阳和8大行星 并且设置好距离和大小 在网上找到相应贴图 添加到assets 将贴图拖动到对
  • Vue中的侦听器:数据变化的秘密揭示

    一 侦听器 vue中想监听数据的变化 一 侦听器watch 如何侦听到某个变量值改变呢 使用watch配置项 watch 可以侦听到data computed属性值的改变 语法 watch 被侦听的属性名 newVal oldVal 快速入
  • 2021全国职业技能大赛-网络安全赛题解析———防火墙篇iptables(超详细)

    2021全国职业技能大赛 网络安全赛题解析 防火墙篇 模块A防火墙的基本规则操作 什么是防火墙 iptables 有问题私信博主 模块A防火墙的基本规则操作 什么是防火墙 iptables IPTABLES 是与最新的 3 5 版本 Lin
  • 2021Robocom决赛---账户安全预警

    拼题 A 系统为提高用户账户的安全性 打算开发一个自动安全预警的功能 对每个账户的每次登录 系统会记录其登录的 IP 地址 每隔一段时间 系统将统计每个账户从多少不同的 IP 地址分别登录了多少次 如果某个账户的登录 IP 超过了 TIP
  • Python如何将字符串(str/json)转换字典(dict)

    一 字符串str转为字典dict 1 使用json进行转换 import json a a 1 b 1 c json loads a print c type c 输出 a 1 c 1
  • GraphQL 中文 -- 一份不标准不专业的翻译

    请移步我的 Github 查看翻译 如有翻译不恰当的地方欢迎指正
  • python 实现GUI(图形用户界面)编程

    Python支持多种图形界面的第三方库 包括 wxWidgets Qt GTK Tkinter Tkinter 模块 Tk 接口 是 Python 的标准 Tk GUI 工具包的接口 Tk 和 Tkinter 可以在大多数的 Unix 平台
  • Springboot整合Swagger2(3.0.0版本)

    天行健 君子以自强不息 地势坤 君子以厚德载物 每个人都有惰性 但不断学习是好好生活的根本 共勉 文章均为学习整理笔记 分享记录为主 如有错误请指正 共同学习进步 文章目录 Swagger2简介 开发环境 实现步骤说明 1 搭建项目 2 引
  • JxBrowser Java浏览器控件

    关键字 JxBrowser能在Windows Linux Mac OS X Intel and PPC based 平台上将Mozilla Firefox浏览器完美地整合到Java AWT Swing应用程序里 该库程序使用Gecko设计引
  • win7/win10电脑屏幕录像工具?

    目前windows系统中 windows 7系统是没有自带的录屏软件 windows 10系统也是对电脑型号有要求 所以在录屏的时候 就需要通过其他三方工具去处理 下载安装 一款优质录屏软件可以给我们的工作以及生活带来不少的便捷 QVE屏幕
  • linux 查看定时任务

    输入cd var spool cron命令 输入ls命令列出cron目录下的定时任务 vi 查看
  • 强制tensorflow使用cpu

    one start import tensorflow as tf cpu tf config list physical devices CPU tf config set visible devices cpu print tf con
  • Java 中SimpleDateFormat类的使用

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 SimpleDateFormat类的介绍 SimpleDateFormat类是一个具体的类 用于以区域设置敏感的方式格式化和解析日期 日
  • VirtualAPK 详解和使用,真牛

    3 1 基本原理 合并宿主和插件的ClassLoader 需要注意的是 插件中的类不可以和宿主重复 合并插件和宿主的资源 重设插件资源的packageId 将插件资源和宿主资源合并 去除插件包对宿主的引用 构建时通过Gradle插件去除插件
  • jeesite整合单点登录

    1 什么是单点登录 单点登录SSO Single Sign On 实际上就是用户在一个系统登录之后 在单点登录的其他客户端 应用 不用重复的登陆 登陆校验交给中央认证服务器去校验 单点登录的应用场景通常为一个大型的系统下有很多小系统 并且这
  • 数据结构之双链表(c语言附完整代码)

    文章目录 一 定义 二 基本运算 三 完整代码 一 定义 双向链表也叫双链表 是链表的一种 它的每个数据结点中都有两个指针 分别指向直接后继和直接前驱 所以 从双向链表中的任意一个结点开始 都可以很方便地访问它的前驱结点和后继结点 示意图
  • Confluence 7 如何修改启动内存

    和 Java 有关的项目通常和内存都有关 最近我们的 Confluence 平台经常挂起 通常的原因可能是内存溢出 在对 Confluence 进行调整之前 需要先查看下内存的配置情况 内存信息 在 Confluence 中 你可以查看当前
  • 【Java】垃圾回收

    目录 概述 什么是垃圾 Garbage 想要学习GC 首先需要理解为什么需要GC Java 垃圾回收机制 Java自动内存管理的优点 关于自动内存管理的担忧 GC 的作用区域 垃圾回收相关算法 重要 标记阶段 引用计数器算法和可达性分析算法