一、Java GC是什么?

Java垃圾回收是对JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver Stop)的保证JVM中的内存空间,防止出现内存泄露和溢出问题,由JVM负责启动。

Java GC机制主要完成3件事:确定哪些内存需要回收,确定什么时候需要执行GC,如何执行GC。

二、Java堆内存

Java内存分配和回收的机制概括的说,就是:分代分配,分代回收。对象将根据存活的时间被分为:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区)。

1、年轻代(Young Generation):对象被创建时,内存的分配首先发生在年轻代(大对象可以直接被创建在年老代),大部分的对象在创建后很快就不再使用,因此很快变得不可达,于是被年轻代的GC机制清理掉(IBM的研究表明,98%的对象都是很快消亡的),这个GC机制被称为Minor GC或叫Young GC。注意,Minor GC并不代表年轻代内存不足,它事实上只表示在Eden区上的GC。

年轻代上的内存分配是这样的,年轻代可以分为3个区域:Eden区(伊甸园,亚当和夏娃偷吃禁果生娃娃的地方,用来表示内存首次分配的区域,再贴切不过)和两个存活区(Survivor 0 、Survivor 1)。

1)绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。Eden区是连续的内存空间,因此在其上分配内存极快;

2)最初一次,当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的);

3)下次Eden区满了,再执行一次Minor GC,将消亡的对象清理掉,将存活的对象复制到Survivor1中,然后清空Eden区;

4)将Survivor0中消亡的对象清理掉,将其中可以晋级的对象晋级到Old区,将存活的对象也复制到Survivor1区,然后清空Survivor0区;

5)当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代,但这只是个最大值,并不代表一定是这个值)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代。

从上面的过程可以看出,Eden区是连续的空间,且Survivor总有一个为空。经过一次GC和复制,一个Survivor中保存着当前还活着的对象,而Eden区和另一个Survivor区的内容都不再需要了,可以直接清空,到下一次GC时,两个Survivor的角色再互换。因此,这种方式分配内存和清理内存的效率都极高,这种垃圾回收的方式就是著名的“停止-复制(Stop-and-copy)”清理法(将Eden区和一个Survivor中仍然存活的对象拷贝到另一个Survivor中),这不代表着停止复制清理法很高效,其实,它也只在这种情况下高效,如果在老年代采用停止复制,则挺悲剧的。

2、年老代(Old Generation):对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代大,能存放更多的对象,在年老代上发生的GC次数也比年轻代少。当年老代内存不足时,将执行Major GC,也叫 Full GC。

可以使用-XX:+UseAdaptiveSizePolicy开关来控制是否采用动态控制策略,如果动态控制,则动态调整Java堆中各个区域的大小以及进入老年代的年龄。

如果对象比较大(比如长字符串或大数组),Young空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)。用-XX:PretenureSizeThreshold来控制直接升入老年代的对象大小,大于这个值的对象会直接分配在老年代上。

三、Java GC机制-回收算法

GC机制的基本算法是:分代收集,这个不用赘述。下面阐述每个分代的收集方法。

1、年轻代-“停止-复制”算法

事实上,在上一节,已经介绍了新生代的主要垃圾回收方法,在新生代中,使用“停止-复制”算法进行清理,将新生代内存分为2部分,1部分 Eden区较大,1部分Survivor比较小,并被划分为两个等量的部分。每次进行清理时,将Eden区和一个Survivor中仍然存活的对象拷贝到 另一个Survivor中,然后清理掉Eden和刚才的Survivor。

这里也可以发现,停止复制算法中,用来复制的两部分并不总是相等的(传统的停止复制算法两部分内存相等,但新生代中使用1个大的Eden区和2个小的Survivor区来避免这个问题)

由于绝大部分的对象都是短命的,甚至存活不到Survivor中,所以,Eden区与Survivor的比例较大,HotSpot默认是 8:1,即分别占新生代的80%,10%,10%。如果一次回收中,Survivor+Eden中存活下来的内存超过了10%,则需要将一部分对象分配到 老年代。用-XX:SurvivorRatio参数来配置Eden区域Survivor区的容量比值,默认是8,代表Eden:Survivor1:Survivor2=8:1:1.

2、老年代-“标记-整理”算法

老年代存储的对象比年轻代多得多,而且不乏大对象,对老年代进行内存清理时,如果使用停止-复制算法,则相当低效。一般,老年代用的算法是标记-整理算法,即:标记出仍然存活的对象(存在引用的),将所有存活的对象向一端移动,以保证内存的连续。

在发生Minor GC时,虚拟机会检查每次晋升进入老年代的大小是否大于老年代的剩余空间大小,如果大于,则直接触发一次Full GC,否则,就查看是否设置了-XX:+HandlePromotionFailure(允许担保失败),如果允许,则只会进行MinorGC,此时可以容忍内存分配失败;如果不允许,则仍然进行Full GC(这代表着如果设置-XX:+Handle PromotionFailure,则触发MinorGC就会同时触发Full GC,哪怕老年代还有很多内存,所以,最好不要这样做)。

3、方法区(永久代)

永久代的回收有两种:常量池中的常量,无用的类信息,常量的回收很简单,没有引用了就可以被回收。对于无用的类进行回收,必须保证3点:

类的所有实例都已经被回收

加载类的ClassLoader已经被回收

类对象的Class对象没有被引用(即没有通过反射引用该类的地方)

永久代的回收并不是必须的,可以通过参数来设置是否对类进行回收。HotSpot提供-Xnoclassgc进行控制

使用-verbose,-XX:+TraceClassLoading、-XX:+TraceClassUnLoading可以查看类加载和卸载信息

-verbose、-XX:+TraceClassLoading可以在Product版HotSpot中使用;

-XX:+TraceClassUnLoading需要fastdebug版HotSpot支持

四、对象什么时候符合垃圾回收的条件?

1、所有实例都没有活动线程访问。

2、没有被其他任何实例访问的循环引用实例。

Java 中有不同的引用类型。判断实例是否符合垃圾收集的条件都依赖于它的引用类型。

引用类型 垃圾收集

强引用(Strong Reference)不符合垃圾收集

软引用(Soft Reference) 垃圾收集可能会执行,但会作为最后的选择

弱引用(Weak Reference) 符合垃圾收集

虚引用(Phantom Reference)符合垃圾收集

GC Scope 示例程序

class GCScope {

GCScope t;

static int i = 1;

public static void main(String args[]) {

GCScope t1 = new GCScope();

GCScope t2 = new GCScope();

GCScope t3 = new GCScope();

// 没有对象符合GC

t1.t = t2; // 没有对象符合GC

t2.t = t3; // 没有对象符合GC

t3.t = t1; // 没有对象符合GC

t1 = null;

// 没有对象符合GC (t3.t 仍然有一个到 t1 的引用)

t2 = null;

// 没有对象符合GC (t3.t.t 仍然有一个到 t2 的引用)

t3 = null;

// 所有三个对象都符合GC (它们中没有一个拥有引用。

// 只有各对象的变量 t 还指向了彼此,

// 形成了一个由对象组成的环形的岛,而没有任何外部的引用。)

}

protected void finalize() {

System.out.println("Garbage collected from object" + i);

i++;

}

五、 JVM参数使用

1、堆内存相关

-Xms 与 -Xmx

-Xms用于指定Java应用使用的最小堆内存,如-Xms1024m表示将Java应用最小堆设置为1024M。-Xmx用于指定Java应用使用的最大堆内存,如-Xmx1024m表示将Java应用最大堆设置为1024m。过小的堆内存可能会造成程序抛出OOM异常,所以正常发布的应用应该明确指定这两个参数。并且,一般会选择将-Xms与-Xmx设置成一样大小,防止JVM动态调整堆内存容量对程序造成性能影响。

-Xmn

通过-Xmn可以设置堆内存中新生代的容量,以此达到间接控制老年代容量的作用,因为没有JVM参数可以直接控制老年代的容量。如-Xmn256m表示将新生代容量设置为256M。假如这个时候额外指定了-Xms1024m -Xmx1024m,那么老年代的容量为768M(1024-256=768)。

-XX:PermSize 与 -XX:MaxPermSize

-XX:PermSize和-XX:MaxPermSize分别用于设置永久代的容量和最大容量。如-XX:PermSize=64m -XX:MaxPermSize=128m表示将永久代的初始容量设置为64M,最大容量设置为128M。

-XX:SurvivorRatio

这个参数用于设置新生代中Eden区和Survivor(S0、S1)的容量比值。默认设置为-XX:SurvivorRatio=8表示Eden区与Survivor的容量比例为8:1:1。假设-Xmn256m -XX:Survivor=8,那么Eden区容量为204.8M(256M / 10 * 8),S0和S1区的容量大小均为25.6M(256M / 10 * 1)。

java gc会回收类么_Java GC 垃圾回收机制相关推荐

  1. java gc回收机制种类_JAVA的垃圾回收机制(GC)

    1.什么是垃圾回收? 垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制. 2.什么时候 ...

  2. java垃圾回收机制标记_Java的垃圾回收机制-垃圾收集算法(一)

    当需要排查各种内存溢出,内存泄漏等问题时,当垃圾收集成为系统达到更高并发的瓶颈时,我们有必要深入GC的原理. image.png 常见垃圾回收算法 在查看垃圾回收具体过程的时候,运行程序加上: -XX ...

  3. java 什么时候进行垃圾回收_Java中垃圾回收有什么目的?什么时候进行垃圾回收?...

    仅提供一个大致的思路: 垃圾回收(gc)的目的是释放堆中不需要保存的对象,达到内存的充分利用. 1.回收哪些对象的判定 垃圾回收最简单的思路是采用引用计数的方式,即记录对象被引用的次数,直到一段时间内 ...

  4. java 垃圾回收机制_Java的垃圾回收机制

    前言 在C++语言中, 程序员必须小心谨慎的处理每一项内存分配, 且内存使用完后必须手动释放曾经占用的内存空间.当内存释放不够完全时, 即存在分配但永不释放的内存块, 就会引起"内存泄漏&q ...

  5. java学习笔记(十一)常用类、反射、垃圾回收

    常用类: System类代表当前java程序的运行平台,Runtime类代表当前java程序的运行时环境. String代表一个不可变的字符串,StringBuffer和Stringbulider代表 ...

  6. java中垃圾收集_Java中垃圾回收机制

    "猪能吃的是湿垃圾,猪不吃的是干垃圾,猪吃了会死的是有害垃圾,卖了能买猪的是干垃圾 ......"最近,上海人民都快被垃圾分类弄疯了.那作为程序员的你,知道在Java中是怎么垃圾回 ...

  7. java api 第一个类是_JAVA之Object常用API

    [Object类.常用API] 主要内容Object类 Date类 DateFormat类 Calendar类 System类 StringBuilder类 包装类 第一章 Object类 1.1 概 ...

  8. Java虚拟机(三)——初识JVM的垃圾回收机制

    前言 对于程序计数器.虚拟机栈.本地方法栈这三个部分而言,其生命周期与相关线程有关,随线程而生,随线程而灭.并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回 ...

  9. 深入了解java虚拟机(JVM) 第六章 垃圾回收算法

    一.标记清除算法 标记清除算法顾名思义,就是将需要回收的对象进行标记,然后进行清除.那么这个算法就有标记和清除两种过程.标记过程主要是通过可达性分析算法进行判断存活对象,然后遍历所有的对象来找到需要回 ...

最新文章

  1. 阿里跳槽拼多多,80万年薪涨到160万,值不值得去?
  2. c语言中存储字符用什么函数,那些C语言中你不知道的字符串函数(坑)
  3. 嗯?原来if可以调用方法的?
  4. 基于matlab/simulink的双电机速度跟踪伺服系统仿真,基于MatlabSimulink的伺服系统仿真pdf.doc...
  5. 《乌合之众》读书笔记(part3)--在群体当中,个人的利益极少会成为强大的动因
  6. jQuery 重要模块 回顾
  7. 【Java数据结构】线索二叉树
  8. unity 后台计时器实现
  9. linux debian硬盘安装,Debian硬盘安装方法
  10. Hadoop YARN(入门) —— Hadoop权威指南5
  11. 国产谷歌地球,地形分析秒杀同款地图软件
  12. C++ Primer 第5版--练习8.4
  13. 如何进行EMC Symmetrix (DMX或者VMAX)的系统健康检查
  14. 内网网段范围_局域网网段到底是什么意思?怎么划分的啊?为什么要划分网段?...
  15. 小程序商品数据对象累加加入购物车缓存导致的数组嵌套在上一层数组中的问题
  16. Android 版本号和分支查看
  17. 【Java EE】从零开始写项目【总结】
  18. spark日志中 Tid是什么
  19. jdk+apache+jboss +mod_jk+openssl--从零开始搭建Linux测试环境
  20. ObjectARX类库简介

热门文章

  1. linux关闭硬件蜂鸣器,Linux Tips: 如何关闭系统的蜂鸣器
  2. Linux系统的磁盘管理
  3. 一周一论文(翻译)——[VLDB 18] Chi:分布式流处理系统下可扩展的、可编程的控制计划模块
  4. 数据库系统概论:第八章 数据库编程
  5. [SOSP 17] Wukong+S : 不断演化的RDF数据的亚毫秒级别的状态流查询
  6. $query = mysql_query_关于$query=mysql_query($query);返回的是什么类型的值的问题的理解 | 学步园...
  7. java之IO流(commons-IO)
  8. 单位员工通讯录管理系统(线性表的应用)
  9. UVALive 4035 - Undetectable Tour(并查集)
  10. 抽奖算法-指定概率的随机