一、内存如何回收

解决如何回收问题,首先需要解决回收对象的问题?什么样的对象需要回收,怎么样的不需要回收?
保证有引用的内存不被释放;回收没有指针引用的内存是Collector的职责,在保证没有指针引用的内存对象中,一般有两种普遍的对象检测策略:

1、引用计数算法

原理:给对象添加一个引用计数器,每当有一个地方引用它时,计数器加1;引用失效时,计数器减1;计数器为0说明可被回收。

缺点:如果对象之间相互循环引用A.instance=B,B.instance=A,如果A=null,B=null,那么A和B的引用计数不变,所以引用计数法不可行

2、可达性分析法

原理:通过一些列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

在Java中GC Roots的对象包括:虚拟机栈中引用的对象,方法区类静态属性引用的对象,方法区常量引用的对象,本地方法栈中JNI引用的对象

图1:可达性分析得到的引用链集合

二、Java中引用的类型

1、强引用:在程序代码之中存在的,类似于“Object obj=new Object()”,主要强引用存在,垃圾收集器就不会回收掉被引用的对象

2、软引用(溢出之前):用来描述一些还有用但是并非必需的对象。在系统将要发生内存溢出之前,将这些对象列进回收范围之中进行第二次回收,类似于缓冲机制使用

3、弱引用(垃圾回收之前):被弱引用的对象只能生存在下一次垃圾收集发生之前

4、虚引用:虚引用对象无法获得对象实例,唯一的目的是在这个对象被收集器回收时收到一个系统通知

三、垃圾回收算法

1、标记-清除算法

图2:标记-清除算法(先标记后清除)

缺点:效率不高,空间会产生不连续的碎片

2、复制算法

图3:复制算法

优点:内存分配时不用考虑内存的碎片问题,实现简单高效

缺点:浪费空间

3、标志清理算法

图4:标志-清理算法

优点:改进了标志清除算法和复制算法的缺点,利用时间来换取空间。

四:内存分配与回收策略

对象的内存分配,往大方向讲,就是在堆上分配,对象主要分配的新生代的Eden区上,当Eden区没有足够的空间进行分配时,虚拟机将会发起Minor GC,MinorGC是指对新生代的垃圾回收动作,Minor GC非常频繁,所以要保证回收速度,一般采用复制算法。相对于Minor GC,Full GC发生在老年代,是指对老年代的收集动作,一次FC,往往伴随着一次Minor GC,因为FC速度一般会比MC慢10倍,所以一般采用标记清理算法。

 大对象通过设置PretenureSizeThreshold参数,大于这个参数的直接进入老生代,因为大对象会导致Eden区域提前触发MC。

 长期存活的对象将进入老年代,虚拟机为每一个对象定义一个Age计数器,在Eden中经过一次MC后如果存活,并且能够被Survivor容纳的话,就会被移到Survivor中,Age=1,在经过一次MC后,+1,当到达MaxTenuringThreshold的时候【默认15】,对象进入老年代【资历变老】,如果在Survivor中相同年龄的所有对象大小的总和大于Survivor的一半时,这个时候年龄大于或者等于这个年龄的对象就可以直接进入老年代,无需等待Age到达MaxTenuringThreshold。

  在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。

  下面解释一下“冒险”是冒了什么风险,前面提到过,新生代使用复制收集算法,但为了内存利用率,只使用其中一个Survivor空间来作为轮换备份,因此当出现大量对象在Minor GC后仍然存活的情况(最极端的情况就是内存回收后新生代中所有对象都存活),就需要老年代进行分配担保,把Survivor无法容纳的对象直接进入老年代。与生活中的贷款担保类似,老年代要进行这样的担保,前提是老年代本身还有容纳这些对象的剩余空间,一共有多少对象会活下来在实际完成内存回收之前是无法明确知道的,所以只好取之前每一次回收晋升到老年代对象容量的平均大小值作为经验值,与老年代的剩余空间进行比较,决定是否进行Full GC来让老年代腾出更多空间。

取平均值进行比较其实仍然是一种动态概率的手段,也就是说,如果某次Minor GC存活后的对象突增,远远高于平均值的话,依然会导致担保失败(Handle Promotion Failure)。如果出现了HandlePromotionFailure失败,那就只好在失败后重新发起一次Full GC。虽然担保失败时绕的圈子是最大的,但大部分情况下都还是会将HandlePromotionFailure开关打开,避免Full GC过于频繁。

对于Xms,Xmx和Xmn参数的说明:

JVM初始分配的堆内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的堆内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;
 空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx 相等以避免在每次GC 后调整堆的大小。-Xmn:设置年轻代大小。年轻代有eden+from survivor+to survivor

整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小

  本文参考了很多前辈整理的资料,在进行自我整理,如有问题,还望指正。

GC和GC分配策略的更多相关文章

  1. 【Java杂货铺】JVM#Java高墙之GC与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾回收技术所围成的"高墙",墙外的人想进去,墙外的人想出来.--<深入理解Java虚拟机> 前言 上一章看了高墙的一半,接下 ...

  2. GC与内存分配策略

    一.GC 第一步:判断对象是否已死?有两种方法:第一种是引用计数法,即给对象添加一个引用计数器,当被引用时,计数器就+1:当引用失效时,就-1:当计数器为0时,代表对象没有被引用.但是计数器的缺点就是 ...

  3. GC之一--GC 的算法分析、垃圾收集器、内存分配策略介绍

    一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...

  4. 内存管理和GC算法以及回收策略

    JVM内存组成结构 JVM栈由堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: JVM内存回收 Sun的JVMGenerationalCollecting(垃圾回收)原理是这样的:把对象分为年青 ...

  5. GC之八--GC 触发Full GC执行的情况及应对策略

    目录: GC之一--GC 的算法分析.垃圾收集器.内存分配策略介绍 GC之二--GC日志分析(jdk1.8)整理中 GC之三--GC 触发Full GC执行的情况及应对策略 gc之四--Minor G ...

  6. 【C# .Net GC】GC内存分配规则

    GC 管理内存分配和回收 公共语言运行时的垃圾回收器为应用程序管理内存的分配和释放. https://docs.microsoft.com/zh-cn/dotnet/standard/automati ...

  7. 《深入理解Java虚拟机》内存分配策略

    上节学习回顾 1.判断对象存活算法:引用计数法和可行性分析算法 2.垃圾收集算法:标记-清除算法.复制算法.标记-整理算法 3.垃圾收集器: Serial:新生代收集器,采用复制算法,单线程. Par ...

  8. 深入理解java虚拟机(2)------垃圾收集器和内存分配策略

    GC可谓是java相较于C++语言,最大的不同点之一. 1.GC回收什么? 上一篇讲了内存的分布. 其中程序计数器栈,虚拟机栈,本地方法栈 3个区域随着线程而生,随着线程而死.这些栈的内存,可以理解为 ...

  9. JVM学习总结四——内存分配策略

    之前几篇我们介绍了jvm的内存模型以及垃圾回收机制,而本篇我们将介绍几个JVM中对象在分配内存是应该遵循的策略.毕竟,想要去优化程序,不仅要考虑垃圾回收的过程,还要从对象内存分配的角度减少gc的代价. ...

  10. <<深入Java虚拟机>>-第三章-垃圾收集器与内存分配策略-学习笔记

    垃圾收集 垃圾收集(Garbage Collection,GC),垃圾收集需要完成的三件事情. 哪些对象需要回收 什么时候回收 如何回收 如何确定对象已死(即不可能在被任何途径引用的对象) 引用计数算 ...

随机推荐

  1. for循环的耗时问题

    结论——用变量来缓存数组长度,效率会更高

  2. nginx: [emerg] directive "upstream" has no opening "{" in /application/nginx-1.6.3/conf/nginx.conf:13 ...

    修改nginx.conf配置文件时,报以下错误: [root@bqh-lb- nginx]# vim conf/nginx.conf [root@bqh-lb- nginx]# sbin/nginx ...

  3. docker 部署oracle

    Oracle数据库服务器Docker映像文档 Oracle Database Server 12c R2是行业领先的关系数据库服务器.Oracle数据库服务器Docker映像包含在Oracle Lin ...

  4. MySQL运行机制原理&架构

    1.MySQL知识普及: MySQL是一个开放源代码的关系数据库管理系统. MySQL架构可以在多种不同场景中应用并发挥良好作用.主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其它的系统 ...

  5. Notes for <<Thinking In Java>>

    String   Thus, when you create a toString( ) method, if the operations are simple ones that the comp ...

  6. shell中判断前一个命令是否执行成功

    ]; then echo "fail" else echo "success" fi 或者 ]; then echo "success" e ...

  7. 【转】SENDING KEY VALUE MESSAGES WITH THE KAFKA CONSOLE PRODUCER

    SENDING KEY VALUE MESSAGES WITH THE KAFKA CONSOLE PRODUCER When working with Kafka you might find yo ...

  8. idea中Git配置,Git的非命令操作

    1.更换Git账户 在idea中File-->Settings-->Appearance-->System Settings-->Passwords,选择不保存密码(Do no ...

  9. flask+uwsgi+supervisor部署流程

    背景: 小鱼最近搞了个工程,python用的2.7(用3也可以),后端使用的是flask,服务器用的linux,使用 flask+uwsgi+supervisor部署 ,查阅相关博客.调试.实操,已经 ...

  10. matlab(4) Logistic regression:求θ的值使用fminunc / 画decision boundary(直线)plotDecisionBoundary

    画decision boundary(直线) %% ============= Part 3: Optimizing using fminunc =============% In this exer ...