文档章节

GC heap 简述

jeff_han
 jeff_han
发布于 2015/11/17 18:23
字数 1856
阅读 179
收藏 4

[原]java gc与heap内存简述

2014-7-9阅读72 评论0

java内存结构和gc算法有很多种,二者也是互相决定的;使用不同的gc算法的jvm会有不同的内存结构。这里就简单整理下常见的sun jvm内存结构和回收算法。

一、java的内存结构

java的内存分为如上几块。

Virtual:如果 -Xms指定的值比-Xmx的小,那么两者的差值就是图上所示的virtual区域

Perm:永久区,主要用来放JVM自己的反射对象,比如类对象和方法对象等。对于spring hibernate这些需要动态类型支持的框架,这个区域需要足够的空间。这个区域不属于heap中。

Young:这里是较新的对象活跃区域。新创建的对象处于Eden区中,经过一次回收的对象会转移到From区;From区再经过一次回收会转移到To区;To区再经过一次回收就会移出Young区转移至Tenured(Old)区。

Tenured(Old):这里是经过数次GC后仍然存活的对象所处区域,池对象(如线程池)就活跃在这个区域中。


二、java gc机制

由于垃圾收集算法在各个虚拟机以及不同的平台上会有不同的实现,所以这里只大概记录一下几个基本的算法。

1.引用计数:

为每一个对象添加一个计数器,计数器记录了对该对象的活跃引用的数量。如果计数器为0,则说明这个对象没有被任何变量所引用,即应该进行垃圾收集。
收集过程如下:
1. 减少被收集对象所引用的对象的计数器的值
2.将其放入延时收集队列之中

引用计数的方法需要编译器的配合。编译器需要为此对象生成额外的代码。如赋值函数将此对象赋值给一个引用时,需要增加此对象的引用计数。还有就是,当一个引用变量的生命周期结束时,需要更新此对象的引用计数器。

由于引用计数无法解决相互引用的情况,所以该算法并没有被任何jvm采用。

2.标记-清除收集器

收集过程分为2个阶段
1. 首先停止所有工作,从根集遍历所有被引用的节点,然后进行标记,最后恢复所有工作
2. 收集阶段会收集那些没有被标记的节点,然后返回空闲链表

标记-清除法的缺点在于
1.标记阶段暂停的时间可能很长,而整个堆在交换阶段又是可访问的,可能会导致被换页换出内存。
2.另外一个问题在于,不管你这个对象是不是可达的,即是不是垃圾,都要在清楚阶段被检查一遍,非常耗时.3,标记清楚这两个动作会产生大量的内存碎片,于是当有大对象进行分配时,不需要触发一次垃圾回收动作

3.拷贝收集器(Copying Collectors)(适用于young generation:PSYoungGen)

    该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。
    将内存分为两个区域(from space和to space)。所有的对象分配内存都分配到from space。在清理非活动对象阶段,把所有标志为活动的对象,copy到to space,之后清楚from space空间。然后互换from sapce和to space的身份。既原先的from space变成to sapce,原先的to space变成from space。每次清理,重复上述过程。

  现在的商业虚拟机都用这种算法来回收新生代,因为新生代的大多数的生命周期都很短暂,所以前面提到的两块相互切换的区域并不需要按照1:1来进行分配。而是分配了一个Eden区,两个Survivor区。大部分对象默认的都是在 Eden区中生成。当垃圾回收时,Eden和其中的一个Survivor区的存活对象将被复制到另外一个Survivor区,当另外一个Survivor区也满了的时候,从Eden和第一个Survivor区复制过来的并且此时还存活的对象,将被复制到tenured generation。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。
    young generation的gc称为minor gc。经过数次minor gc,依旧存活的对象,将被移出young generation,移到tenured generation

优点:copy算法不理会非活动对象,copy数量仅仅取决为活动对象的数量。并且在copy的同时,整理了heap空间,即,to space的空间使用始终是连续的,内存使用效率得到提高。
缺点:默认情况下Eden:Survivor=8:1, 所以总会有100-(80+10)%的新生代内存会被浪费掉。

4.标记-整理收集器(Mark-Compact Collectors)(适用于存放生命周期较长对象的tenured generation:PSOldGen)

标记整理收集器,通过融合了标记-清除收集器和拷贝收集器的优点,很好的解决了拷贝收集策略中,堆内存浪费严重的问题。

标记整理收集器分为2个阶段
1. 标记阶段, 这个阶段和标记-清除收集器的标记阶段相同
2. 整理阶段, 这个阶段将所有做了标记的活动对象整理到堆的底部(有点像是磁盘碎片整理,呵呵)

    生命周期较长的对象,归入到tenured generation。一般是经过多次minor gc,还依旧存活的对象,将移入到tenured generation。(当然,在minor gc中如果存活的对象的超过survivor的容量,放不下的对象会直接移入到tenured generation)tenured generation的gc称为major gc,就是通常说的full gc。由于tenured generaion区域比较大,而且通常对象生命周期都比较长,所以这部分的gc时间比较长。
    minor gc可能引发full gc。当eden+from space的空间大于tenured generation区的剩余空间时,会引发full gc。这是悲观算法,要确保eden+from space的对象如果都存活,必须有足够的tenured generation空间存放这些对象。

三、其它gc补充

商业jvm普遍使用这个方法来判断对象是否可达:通过类的静态变量及栈中变量依次遍历可及的为存货对象。

finalize()方法:这个方法会在gc时被调用。但是gc并不保证什么时候销毁对象,即使调用System.gc()方法,也只是通知它进行回收,jvm并不保证立刻执行它。有时候如果在这个方法里写入不恰当的代码引用了一些对象可能会导致gc永远不会回收对象,因此不推荐在这里进行流关闭之类c++析构函数干的工作。


© 著作权归作者所有

jeff_han
粉丝 12
博文 37
码字总数 19577
作品 0
海淀
部门经理
私信 提问
JVM学习之:GC的算法简述

由于垃圾收集算法在各个虚拟机以及不同的平台上会有不同的实现,所以开头先大概讲解一下几个基本的算法 1. 引用计数(Reference Counting) 为每一个对象添加一个计数器,计数器记录了对该对象的...

sun7545526
2012/08/14
0
0
Erlang进程堆垃圾回收机制

作者:http://blog.csdn.net/mycwq 每个Erlang进程创建之后都会有自己的PCB,栈,私有堆。erlang不知道他创建的进程会用到哪种场合下,所以一开始分配的内存比较小。如果分配的空间不够了,e...

天天顺利
2015/05/26
89
0
Linux下实用的JAVA内存泄露监控命令及工具

一、Linux 命令 1、jstack (linux下特有) 可以观察到jvm中当前所有线程的运行情况和线程当前状态 jstack 2083 输出内容如下: 2、jmap (linux下特有,也是很常用的一个命令) 观察运行中的...

rechardchensir
2018/11/23
940
0
jvm内存参数设置

1. Heap设定与垃圾回收 Java 内存分为3个区,Young,Old和Permanent。Young保存刚实例化的对象。当该区被填满时,GC会将对象移到Old区。 通常把前两个区域叫做堆区(Heap),Permanent区则负责保...

晨曦之光
2012/04/25
1K
0
Dalvik 内存调整及监控报告

原文转自:http://marshal.easymorse.com/archives/3942 目前开发android应用,主要问题在内存的使用上,需要熟悉andorid虚拟机Dalvik的内存特性。以下是Nexusone Android 2.2(非官方的CM衍...

无鸯
2011/09/07
2.7K
1

没有更多内容

加载失败,请刷新页面

加载更多

Spring Security 自定义登录认证(二)

一、前言 本篇文章将讲述Spring Security自定义登录认证校验用户名、密码,自定义密码加密方式,以及在前后端分离的情况下认证失败或成功处理返回json格式数据 温馨小提示:Spring Security...

郑清
25分钟前
2
0
php yield关键字以及协程的实现

php的yield是在php5.5版本就出来了,而在初级php界却很少有人提起,我就说说个人对php yield的理解 Iterator接口 在php中,除了数组,对象可以被foreach遍历之外,还有另外一种特殊对象,也就是继承...

冻结not
38分钟前
3
0
servlet请求和响应的过程

本文转载于:专业的前端网站➥servlet请求和响应的过程 1.加载 Servlet类被加载到Java虚拟机中,并且实例化。在这个过程中,web容器(例如tomcat)会调用Servlet类的公开无参构造函数,产生一...

前端老手
38分钟前
3
0
golang 1.13 errors 包来了,不用写“err 气功波”代码

引 这篇是对 errors 包 的姿势挖掘 气功波错误代码 从 http.Get()返回的错误 判断 syscall.ECONNREFUSED 错误.以前要对 go 标准库 error 结构有点熟悉,才能写出下面的代码 func CmdErr(err ...

guonaihong
42分钟前
28
0
喜玛拉雅已听书单

时间倒序排 书名 作者 状态 唐砖 孑与2 进行中 死灵之书(克苏鲁神话合集) 阿卜杜拉·阿尔哈萨德 进行中 赡养人类 刘慈欣 完结 赡养上帝 刘慈欣 完结 中国太阳 刘慈欣 完结 中国太阳 刘慈欣...

Alex_Java
43分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部