一、对象的生命周期

java对象在虚拟机中经过三个过程:

1.首次加载类型 =>  初始化类变量

2.创建对象 (有四种方式)

2.1  new 操作

2.2 Class或java.lang.reflect.Constructor.newInstance()

2.3 调用对象的clone()

(类需要实现java.lang.Cloneable接口,才能调用close(),如果是Object.clone(),则返回一个新对象,并新对象的属性由原对象来赋值,

注意,如果对象的属性是对象类型,则新对象的属性也只是赋值对象引用,既是Object.clone()只是浅复制。)

2.4 对象的反序列化 ObjectInutStream.readObject()

(先分配内存,再初始化实例变量的值,

如果没有显式地调用父类的构造方法,初始化对象的构造方法时,先默认调用父类的无参构造方法)

3. 垃圾收集

二、对象的垃圾收集

对象是创建在堆中的,一般堆是分代存储对象,分为三个部分:

1. 年轻代(分为 Eden,  From Survivor Space,  To Survivor Space)

2. 年老化(步骤:标记(MARK),消除(SWEEP),合并(Compact)

3. 永久代

年经化

新创建对象是,会先放到Eden区,当Eden区的空间满了,会 把Eden区存活的对象搬到From区,

下次Eden区又满了,会把Eden和From区的存活对象搬到To区,

下次Eden区又满了,会把Eden和To区的存活对象搬到To区,以此类推。

当多次(默认15次)垃圾收集之后,对象还在年轻代,则会搬到年老代。

年轻代每次垃圾收集又称Young GC

年老代

当年老代里的空闲空间存在碎片,则使得没有足够空间时去存放新放进来的年老代对象,需要进行一个Full GC,需要垃圾收集所有对象,将存活的对象移动到空间的前部分。标记阶段把所有存活的对象标记出来,清除阶段释放所有死亡的对象,合并阶段 把所有活着的对象合并到年老代的前部分,把空闲的片段都留到后面。设计的选型为合并,减少内存的碎片。

虚拟机参数:

-Xms512m  堆heap初始化值

-Xmx512m  堆heap最大值

-Xmn300m  年轻代的堆heap大小值

-Xss512k     每个线程的Stack大小

-XX:PermSize=64m  永久代的最小值

-XX:MaxPermSize=64m  永久代的最大值

-XX:NewSize=100m 设置年轻代的大小值

-XX:MaxNewSize=100m 设置年轻代的最大值

-XX:NewRatio=4  即  年轻代 : 年老代 = 1:4

-XX:SurvivorRatio=4  即 Eden : From : To Survivor Space = 4 : 1 : 1

-XX:+UseConcMarkSweepGC  开启虚拟机收集器:CMS,默认启动的回收线程数是(CPU数量+3)/ 4,也就是当CPU在4个以上时,并发回收时垃圾收集线程最多占用不超过25%的CPU资源。但是当CPU不足4个时(譬如2个),那么CMS对用户程序的影响就可能变得很大,如果CPU负载本来就比较大的时候,还分出一半的运算能力去执行收集器线程,就可能导致用户程序的执行速度忽然降低了50%,不过一般服务器都有8核或16核或更高。

-XX:CMSInitiatingOccupancyFraction=58 ,默认值是68,即年老代的使用比率达到68%后,执行CMS垃圾收集。

-XX:+PrintGCDetails  垃圾收集打印收集详情

-XX:+PrintGCTimeStamps  垃圾收集打印详细时间,只是打印垃圾收集的持续时间

-XX:+PrintGCDateStamps 垃圾收集打印出收集的某个时间时刻,具体到哪个一分哪一秒发生的垃圾收集。

-Xloggc:${LOGS_DIR}/gc.log  垃圾收集打印的日志路径

为保留内存溢出的场景,可使用以下参数:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\service\test-service\gc.hprof

当内存溢出时,内存的对象使用情况,会输出到文件 gc.hprof ,我们可以使用ecplise的MAT工具分析内存的对象使用情况。

使用jmap命令导出jvm堆的内存快照,导出结果文件使用MAT工具分析:

jmap -dump:format=b,file=/opt/deploy-service/heap.bin pid

使用-Xloggc:./logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
gc.log的内容:

2017-06-12T11:54:57.955+0800: 11.556: [GC2017-06-12T11:54:57.955+0800: 11.556: [DefNew: 13886K->721K(14656K)
, 0.0080210 secs] 43593K->30940K(47044K), 0.0081070 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

其中
GC,是年经代的垃圾收集;
[DefNew: 13886K->721K(14656K), 0.0080210 secs],DefNew(不同的GC这个年轻代名字会稍有不同)年轻代占内存14656K,已使用13886K->721K,减少了13000K,历时0.0080210秒;
43593K->30940K(47044K),堆占内存47044K, 已使用43593K->30940K,减少了13000K;
从以上可以看出经过年轻代垃圾收集,年轻代的对象是真实收集掉了,而不是转到年老代。

2017-06-12T11:55:00.888+0800: 14.489: [Full GC2017-06-12T11:55:00.888+0800: 14.489: [Tenured: 26390K->25631K(32388K)
, 0.1790040 secs] 29094K->25631K(47044K), [Perm : 32127K->32127K(32128K)], 0.1801110 secs] [Times: user=0.18 sys=0.00
, real=0.18 secs]

其中
Full GC,年老代和永久代的垃圾收集;
[Tenured: 26390K->25631K(32388K), 0.1790040 secs],Tenured年老代(也有叫年终代),其余部分跟年轻代垃圾收集类似;
[Perm : 32127K->32127K(32128K)], 0.1801110 secs],Perm永久代,其余部分跟年轻代垃圾收集类似;
[Times: user=0.18 sys=0.00, real=0.18 secs],user是用户态耗费的时间,sys是内核态耗费的时间,real是整个过程实际花费的时间,user + sys表示一个CPU需要的时间,由于可能有多核CPU的情况,可能user + sys会比real多几倍,不过我这里是单核虚拟机,所以时间是相等的。

垃圾收集的两种方式

虚拟机区分对象和垃圾有两个基本的方式:引用计数和跟踪。

1 引用计数

垃圾收集器为每个对象保存一个计数来区分活动对象和垃圾对象,这个方法可以很快地执行,但无法检测出循环引用 的情况(即两个或多个对象相互引用的情况),所以这个方法已被放弃不用了

2 跟踪收集器

跟踪收集器从根节点开始的对象引用 图,在追踪中遇到的对象以某种方式打上标记。当追踪结束时,没有被标记的对象则是不可触及的,从而可以被收集。

对象的状态

上面说过,对象在垃圾收集需要经过标记,再进行清除,基于这点,在虚拟机垃圾收集看来,对象有3种状态:可触及的,可复活的,不可触及的

1 可触及的

对象被创建后,就处理于可触及状态,因为从根节点扫描该对象,对象是可以被追踪到的,每个对象都是从可触及状态开始它的生命周期。

2 可复活的

一旦程序释放了所有对该对象的引用,经过第一次从根节点的全部扫描,触及不到该对象,垃圾收集器必须检查已检测出不再被引用的对象是否声明了终结方法finalize(),因为有可能执行了所有不再被引用 的对象的终结方法后,该对象有可能“复活”了,被复活不仅是被该对象本身复活,而是指所有不再被引用 的对象的终结方法里,有可能需要用到该对象来释放、处理对象的终结处理而复活了该对象。

在第一次扫描之后,没有被引用 的对象,会被收集器加以标记。

3 不可触及的

经过第一次从根节点扫描,而且执行了不再被引用 的对象的终结方法后,第二次只会扫描第一次扫描出的不再被引用 的对象结果,如果经过第二次追踪,还是不再被引用的对象,则是不可触及状态,已经是可以被垃圾收集器回收内存了。

的1.2之前,对象对于垃圾收集器来说只有以上3种状态。

在1.2以后,扩展了3种状态: 软可触及、弱可触及和虚可触及,则对象是有6种可触及状态的。

1 强可触及

对象可以从根节点不通过任何引用对象搜索到。对象生命周期从强可触及 状态开始,并且只要有根节点或者另外一个强可触及 对象引用它,就保持强可触及状态。垃圾收集器不会回收强可触及状态占据的空间的

2 软可触及的(SoftReference)

对象不是强可触及的,但是可以从根节点开始 通过 一个或多个软引用对象触及。垃圾收集器可能回收软可触及的对象所占据的空间。如果发生了收集,会清除软可触及的软引用对象,并该软引用对象加入队列

3 弱可触及(WeakReference)

对象既不是强可触及,也不是软可触及的,但是可以从根节点开始 通过 一个或多个弱引用对象触及。垃圾收集器必须回收弱可触及的对象所占据的空间。如果发生了收集,会清除弱可触及的弱引用对象,并该弱引用对象加入队列

4 可复活的

对象既不是强可触及的、软可触及的,也不是弱可触及,但是仍然可以通过执行某些终结方法复活到这几种状态之一

5 虚可触及(影子可触及,PhantomReference)

对象既不是强可触及 的、软可触及的,也不是弱可触及,并已经 被断定不会被 任何终结方法复活,可以从根节点开始 通过 一个或多个虚引用对象触及。一旦一个虚可触及引用的对象变成 虚可解及状态,垃圾收集器立即把该引用对象加入队列。垃圾收集器从不会清除一个虚引用,所有的虚引用都必须由程序明确地清除。

6 不可触及

一个对象不是强可触及、软可触及、弱可触及,也不 是虚可触及,并且它不可复活。不可触及 的对象已经 准备好被回收。

Java虚拟机:垃圾收集相关推荐

  1. Java虚拟机垃圾收集器初步学习

    Java虚拟机-垃圾收集器 1.概述 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现.     这里讨论的收集器基于JDK 1.7 Update 14之后的HotSpot虚拟机 ...

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

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

  3. Java虚拟机------垃圾收集器

    JVM系列最核心的文章没有之一: 引用 强引用 只要引用存在,垃圾回收器就永远不会回收.当内存空足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引 ...

  4. 读书笔记--Java虚拟机垃圾收集算法

    前言 熟悉虚拟机的垃圾收集算法有助于我们更好的了解Java内存的分配策略.对我来说,以前也有去了解过虚拟机相关的知识点,但是比较零碎.这次拜读<深入理解Java虚拟机>,真是相当后悔自己为 ...

  5. 深入理解Java虚拟机——垃圾收集器与内存分配策略

    文章目录 对象已死? 引用计数算法 可达性分析算法 再谈引用 强引用: 软引用: 弱引用: 虚引用: 回收方法区 垃圾收集算法 标记 - 清除算法 缺点: 标记 - 复制算法 标记 - 整理算法 分代 ...

  6. Java虚拟机垃圾收集算法

    1.标记-清除算法 标记-清除算法分为 "标记" 和 "清除" 两个步骤:首先标记出所有需要回收的对象,然后在标记完成后统一回收所有被标记的对象,是垃圾收集算法 ...

  7. java虚拟机学习笔记之垃圾收集(下)

    ★引用计数收集器 这种方法中,堆中每个对象都有一个引用计数.当一个对象被创建了,并且指向该对象的引用被分配给一个变量,这个对象的引用计数被设置成1.当这个对象的引用赋值给其他任何一个变量的时候,这个变 ...

  8. 深入理解Java虚拟机—低延迟垃圾收集器

    上一篇:深入理解Java虚拟机-垃圾收集器 下一篇:深入理解Java虚拟机-垃圾收集器适用场景 这一篇讲的是低延迟垃圾收集器 衡量垃圾收集器的三项最重要的指标是:内存占用(Footprint).吞吐量 ...

  9. 深入理解Java虚拟机—Java虚拟机内存

    之前的内容: 上一篇:深入理解Java虚拟机-Java历史以及Java虚拟机历史 下一篇:深入理解Java虚拟机-垃圾收集算法 一.运行时数据区分为五个区域 1. 程序计数器 他可以看作是当前线程所执 ...

最新文章

  1. 图像浏览软件_FastStone Image Viewer5.5版
  2. 医学假阴性?看看在机器学习中如何用来衡量分类模型的效果(附代码)
  3. python如何爬虫网页数据-如何轻松爬取网页数据?
  4. Altair PollEx 2020中文版
  5. 说说Broker服务节点、Queue队列、Exchange交换器?
  6. boost::qvm::is_scalar相关的测试程序
  7. SQL Server 无法生成 FRunCM 线程。请查看 SQL Server 错误日志和 Windows 事件日志(转)...
  8. WinForm中导出Excel
  9. 各種語系的unicode對應以及local編碼方式
  10. eoe·Android 开发门户 - android开发者的必备网站
  11. 学python能做什么类型的工作-学Python要先学什么?Python入门方法
  12. python初识(2)
  13. android sqlite数据库 emoji表情,Android的Emoji表情
  14. 常用的学术论文研究方法(着重讲解文献法)
  15. 简单聊聊利用DNS服务器提供单一入口
  16. 关于Win8引导菜单风格切换
  17. UVA437 巴比伦塔 The Tower of Babylon
  18. 搞IT的不可不知道的仙童“八叛徒”的故事(转)
  19. CentOS 7 从下载到安装
  20. My97DatePicker时间控件

热门文章

  1. 安装图解:Linux Mint 4.0(Daryna)(或者说完美的桌面系统)
  2. [网络安全自学篇] 二.Chrome浏览器保留密码功能渗透解析及登录加密入门笔记
  3. LeCo-206反转链表
  4. 【webGoat】Path traversal
  5. 第二篇 第三章防火防烟分区检查(一)
  6. 腾讯优图开源项目全景图!
  7. 串口转以太网与监控软件modbusTCP客户端通信配置
  8. GSCoolink GSV6201 TypeC/DP to HDMI2.1
  9. 【离散数学】编程练习:求偏序集中的极大元与极小元
  10. 要考驾照科目二了,好紧张