JAVA内存模型及垃圾回收自我总结
本文为原创,根据《深入理解java虚拟机》和自己的一些理解进行整理,单纯和看其他人的博客感觉不如自己一点点的画和记录来的印象深刻。
JAVA内存模型:
上图中:局部变量表所需的内存在编译期已经分配完成 表达有误, 准确的表达应该是:局部变量表所需的内存在编译期就已经计算完成(即需要在运行时分配多大内存)。
判断对象是否已死(可以回收)的算法
从永久代到年轻代的引用可以被当成 GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉
方法区(永久代)回收的相关说明:
永久代的垃圾回收主要两部分内容:废弃的常量和无用的类。 废弃的常量:无任何对象引用此常量。 无用的类:、该类所有实例已经被回收(堆中不存在该类的任何实例)。
、加载该类的ClassLoader已经被回收。
、给类对应的Class对象没有任何地方呗引用,无法在任何地方通过反射访问该类的方法
垃圾收集的算法:
1、标记 - 清除算法
包含标记和清除2个阶段,是最基础的算法。标记就是标记出那些已经可以被回收的对象,在标记完成后进行清楚,此算法效率不高而且会产生内存碎片,当程序在以后的运行中需要分配一块大的连续的内存时可能因为内存碎片的问题而提前触发再次垃圾回收。
过程示意图如下:
2、复制算法(新生代采用的算法之一)
为了解决标记-清除 算法 的效率问题的,将内存划为多块,在标记完一块区域的对象的存活状态后,将存活的对象拷贝到另外一块上,然后将之前的那块一次清理掉。
在新生代上对象存活期很短,并且98%的对象是朝生夕死,所以在内存的划块上不需要1:1进行划分,hotspot虚拟机默认按照Eden-80%,两块Survivor各10%进行划分(8:1),其中Eden和一块Survivor空间用来存放新生代的对象,还有一块用来复制垃圾回收时Eden和另外一块Survivor的存活对象,然后一次清除调用Eden和那块Survivor内存,下次垃圾回收时这2块Survivor的功能互相调换。当一块Survivor不够装下存活的对象时,则会向老年代的分配担保机制(借内存)进入到老年代。
复制算法的示意图:
3、标记 - 整理算法
相比标记-清理算法,此算法解决了标记-清理算法的内存碎片问题,清理完可回收的对象后会对该内存块进行整理。
算法示意图:
4、分代收集算法
当前商业虚拟机都采用此算法,其实说这是算法还不如说是一个将前面3个算法在新生代和老年代上应用不同算法的一个策略,新生代采用复制算法,老年代采用“标记-清除”或者“标记-整理”算法。
垃圾回收器(垃圾收集算法的具体实现)
HotSpot 1.6版Update22的收集器入下所示:
上面部分是新生代的垃圾回收器,下面部分是老年代的垃圾回收器,中间的连线表示这2个回收器可以配合一起使用。
新生代的垃圾收集器
1、Serial收集器(复制算法)
此收集器是最基本的,也是历史最悠久的收集器,是JDK1.3.1之前新生代的唯一选择,该收集器的缺点是垃圾收集器回暂停用户的所有线程来进行单线程的垃圾收集,后面的其它收集器基本就是在此收集器的基础进行优化修改而来,在Client模式下运行还是可以的接受的。
运行示意图如下:
2、ParNew收集器(复制算法)
Serial的多线程版本,是许多运行在Server模式下的虚拟机中新生代收集器的首选。在多核心的服务器上运行优势明显,默认开启的线程=CPU核心数,
通过使用-XX:ParallelGCThreads参数可以来限制垃圾收集的线程数。
运行示意图:
3、Parallel Scavenge收集器(复制算法)
跟parNew收集器差不多,但与上面2个收集器的关注点不同,前面的2个更多的关注用户的停顿时间,而此收集器更关注CPU的吞吐量(吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),
其中有2个参数可以控制这个吞吐量,1、-XX:MaxGCPauseMillis xxxx,控制最大垃圾收集停顿时间(x>0的毫秒数)。2、-XX:GCTimeRatio XXX,设置吞吐量大小(设置一个0<x<100的整数,表示垃圾收集器时间占总时间的比率,相当于吞吐量的倒数)。
另外,此收集器还有一个参数-XX:+UseAdaptiveSizePolicy,如果打开这个开发,则新生代的大小(-Xmn)、Eden、Survivor(-XX:SurvivorRatio)、晋升老年代的对象年龄(-XX:PretenureSizeThreshold)等参数就不需要手工指定了,虚拟机会根据系统的运行情况来动态调整。
运行示意图:
老年代收集器
1、Serial Old收集器(标记-整理算法)
新生代serial的老年代版本,主要有如下2个用途:1、在JDK1.5以及之前的版本搭配新生代的Parallel Scavenge收集器使用。2、作为CMS收集器发生Concurrent Mode Failure的一个后备方案。
2、Parallel Old收集器(标记-整理算法)
新生代Parallel Scavenge收集器的老年代版本,在JDK1.6的版本中才提供,只能和新生代的Parallel Scavenge收集器搭配使用。
3、CMS收集器(标记-清除算法)
Concurrent Mark Sweep,一种以获取最短回收停顿时间为目标的收集器,具有并发低顿挫的特点,但其也有几个缺点:
①对CPU资源很敏感(需要跟用户线程并发执行)。
②无法处理浮动垃圾(Floating Garbage,在标记过程后产生的垃圾),CMS需要预留足够的内存空间给用户线程使用,所以CMS收集器在老年代使用了68%的空间后被激活(可以通过-XX:CMSInitiatingOccupancyFranction参数来配置触发百分比),如果在运行过程中预留的内存无法满足程序需要,则会出现一次“Concurrent Mode Failure”失败并启用后备预案(Serial Old收集器)进行Full GC。
③由于采用标记-清除算法,会产生内存碎片,不过可以配置-XX:+UseCMSCompactAtFullCollection开关让Full GC后进行一次碎片整理,也可以使用-XX:CMSFullGCsBeforeCompaction来设置执行多少次Full GC自动来一次碎片整理。
共分为4个过程:
㈠、初始标记
需要暂停用户线程,但过程很快。
㈡、并发标记
㈢、重新标记
需要暂停用户线程,对前面的标记进行修正。
㈣、并发清除
运行示意图:
4、G1收集器
Garbage First收集器是当前收集器技术发展的前沿成果,在JDK1.6_update14提供试用,是一款面向服务器应用的垃圾收集器。
主要有如下特点:
● 并发运行
● 基于标记-整理算法,不会产生空间碎片
● 非常精确的控制停顿,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在收集上的时间不超过N毫秒,这几乎是实时JAVA(RTSJ)垃圾收集器的特征了
● 将整个堆(新生代、老年代)划分为多个大小固定的独立区域,并与这些区域为单位进行垃圾回收,避免对整个堆进行全量回收操作,并对这些区域进行优先级维护和回收。
进入老年代的几种途径
1、在新生代GC过程中survivor空间不够,通过老年代的分配担保机制提前转入老年代。
2、超过参数PretenureSizThreshold设置的值的大对象直接进入老年代,所谓大对象就是需要大量连续内存空间的java对象(例如很长的字符串和大数组)。
3、长期存活的新生代对象进入老年代,如果对象在一次Minor GC(新生代GC)后仍存活并且能被survivor容纳后被移动到Survivor中后将该对象的年龄+1,当它的年龄达到一定程 度(默认15)后就会晋升到老年代,这个阀值可以通过-XX:MaxTenuringThreshold来设置。
4、虚拟机并不总要求对象达到XX:MaxTenuringThreshold的值后才晋升老年代,如果在Survivor空间中相同年龄所有对象大小总和大于Survivor空间的一半,年龄大于或者等于 该年龄的对象就可以直接进入老年代。
JAVA内存模型及垃圾回收自我总结的更多相关文章
- Java内存模型与垃圾回收
1.Java内存模型 Java虚拟机在执行程序时把它管理的内存分为若干数据区域,这些数据区域分布情况如下图所示: 程序计数器:一块较小内存区域,指向当前所执行的字节码.如果线程正在执行一个Java方法 ...
- java内存模型和垃圾回收(收藏)
java内存模型: https://www.cnblogs.com/handsomeye/p/5442879.html java垃圾回收 http://www.cnblogs.com/handsome ...
- Java内存模型与垃圾回收笔记
内存模型 栈. 局部变量(基本类型)与对象引用:线程隔离.每个方法执行时会创建一个栈帧,存储局部变量等. 堆. 对象实例:线程共享. 方法区.类信息.常量(final).静态变量.符号引用: 线程共享 ...
- java内存模型和垃圾回收
摘抄并用于自查 JVM内存模型 1. Java程序具体执行的过程: Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀) 由JVM中的类加载器加载各个类的字节码文 ...
- Java虚拟机内存模型及垃圾回收监控调优
Java虚拟机内存模型及垃圾回收监控调优 如果你想理解Java垃圾回收如果工作,那么理解JVM的内存模型就显的非常重要.今天我们就来看看JVM内存的各不同部分及如果监控和实现垃圾回收调优. JVM内存 ...
- 【Java_基础】JVM内存模型与垃圾回收机制
1. JVM内存模型 Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间. JVM内存模型如下图所示 1.1 程序计数器 程序计数器( ...
- 程序猿的日常——JVM内存模型与垃圾回收
Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础--这就是JVM.在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情 ...
- JVM内存模型和垃圾回收
Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础——这就是JVM.在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情 ...
- (转载)JVM中的内存模型与垃圾回收
转载自微信公众号:Java高级架构(Java-jiagou)-----看完这篇文章,我奶奶都知道JVM中的内存模型与垃圾回收了! 六.内存模型 6.1 内存模型与运行时数据区 Java虚拟机在执行J ...
随机推荐
- 【转】各种 NoSQL 的比较
转自 : http://linux.cn/article-2177-1.html 来源:Linux中国 原文:http://linux.cn/article-2177-1.html 即使关系 ...
- Visual Studio 2013中引入Web Service的简单方法visual studio 引用 wsdl
http://blog.csdn.net/wangzhongbo_24/article/details/49954191 Web Service有三种表示方式 三种方式分别为WSDL.Endpoint ...
- JavaScript:Events
ylbtech-JavaScript:Events 1.返回顶部 JavaScript 事件参考手册 事件通常与函数配合使用,这样就可以通过发生的事件来驱动函数执行. 事件句柄 HTML 4.0 的新 ...
- 使用C#反射机制访问类的私有成员【转】
首先我必须承认访问一个类的私有成员不是什么好做法.大家也都知道私有成员在外部是不能被访问的.而一个类中会存在很多私有成员:如私有字段.私有属性.私有方法.对于私有成员访问,可以套用下面这种非常好的方式 ...
- centos 下 mysql+keepalived实现双主自由切换
目录 ip规划 mysql双主配置 keepalived配置 mysql1中keepalived的配置 mysql2中keepalived的配置 VIP漂移检测 本文的目的是搭建一个互为主从的mysq ...
- win10安装jdk以及配置环境变量
本人使用的jdk版本:jdk-8u171-windows-x64.exe, 1.安装jdk: 双击 jdk-8u171-windows-x64.exe ,然后就是简单的安装流程,安装文件位置建议保持默 ...
- capwap学习笔记——初识capwap(一)
2 初识CAPWAP 2.1 CAPWAP简介 说了半天CAPWAP,连全称都还没说,汗-- CAPWAP--Control And Provisioning of Wireless Access P ...
- 利用NATAPP隧道解决微信公众号开发之本地调试难题
一.问题 众所周知,微信公众号开发需要公网的有效域名和80端口,本机当然互联网是访问不了的.那么我们难道去一个公网的服务器去开发吗?那样是不是太土了. 答案当然是,NO 当然我们在做微信支付的时候,有 ...
- (转)Unity Assets目录下的特殊文件夹名称(作用和是否会被打包到build中)
原文:http://wiki.unity3d.com/index.php/Special_Folder_Names_in_your_Assets_Folder 1.隐藏文件夹以.开头的文件夹会被Uni ...
- [Angular] Use Angular components in AngularJS applications with Angular Elements
When migrating AngularJS (v1.x) applications to Angular you have different options. Using Angular El ...