现代JVM内存管理方法的发展历程,GC的实现及相关设计概述(转)

JVM区域总体分两类,heap区和非heap区。heap区又分:Eden Space(伊甸园)、Survivor Space(幸存者区)、Tenured Gen(老年代-养老区)。
非heap区又分:Code Cache(代码缓存区)、Perm Gen(永久代)、Jvm Stack(java虚拟机栈)、Local Method Statck(本地方法栈)。

HotSpot虚拟机GC算法采用分代收集算法:

1、一个人(对象)出来(new 出来)后会在Eden Space(伊甸园)无忧无虑的生活,直到GC到来打破了他们平静的生活。GC会逐一问清楚每个对象的情况,有没有钱(此对象的引用)啊,因为GC想赚钱呀,有钱的才可以敲诈嘛。然后富人就会进入Survivor Space(幸存者区),穷人的就直接kill掉。

2、并不是进入Survivor Space(幸存者区)后就保证人身是安全的,但至少可以活段时间。GC会定期(可以自定义)会对这些人进行敲诈,亿万富翁每次都给钱,GC很满意,就让其进入了Genured Gen(养老区)。万元户经不住几次敲诈就没钱了,GC看没有啥价值啦,就直接kill掉了。

3、进入到Genured Gen(养老区)的人基本就可以保证人身安全啦,但是亿万富豪有的也会挥霍成穷光蛋,只要钱没了,GC还是kill掉。

分区的目的:新生区由于对象产生的比较多并且大都是朝生夕灭的,所以直接采用标记-清理算法。而养老区生命力很强,则采用复制算法,针对不同情况使用不同算法。

非heap区域中Perm Gen中放着类、方法的定义,
jvm Stack区域放着方法参数、局域变量等的引用,方法执行顺序按照栈的先入后出方式。

现代JVM内存管理方法及GC的实现和主要思路

谨以此文纪念已经辞世的C语言之父,Dennis Ritchie。无论世事如何变迁,无论日月如何更替,您的光辉成就都照耀着现代计算机技术发展之路。

提到现代JVM内存管理,就不能不提到一个意义深远的东西,C语言。C语言最为人诟病,但是也是C语言最让人神往的,就是它的内存管理机制。在C语言中,程序员可以自由的控制内存,自己决定内存里写0还是写1.所谓的数据类型转换,在C语言看来,不过就是内存里的几次复制以及排列位置的不同,仅此而已。

然而随着应用规模的不断增大,无论是盘根错节的对象耦合关系,还是巨大的内存使用量,都让开发人员麻爪。动辄几个GB的内存总量,动辄成千上万的内存对象数量,都不再是一个人乃至十个人可以控制的范围了。况且,百密一疏,只要有一点点内存泄露,随着时间的推移,都有可能变成无比的灾难。OOM之类的问题,在程序员眼里,早已经是家常便饭,谁还没溢出过内存呢,是吧。

的确是有高手可以控制好内存,但是不是所有人。那么,大规模团队化开发的时候,如何保证内存使用不出现问题呢?代码走查?人工校验?反复测试?这些能不能行的通先不谈,就算可行,巨大的工作量也可以让所有合同超期到下个世纪。于是有人提出了一个想法。可以不可以让一部分高手写出完善的内存管理模块,再加上一堆各式各样的类库和标准,最后构成一个庞大的运行时?

这一想法被无数语言团队采用。第一个实现的,就是James Gosling领导的Java团队。Java的目标是Write Once,Run Anywhere.估计他们在咖啡馆喝咖啡的时候一时写错了,应该是Debug Anywhere,这才符合现在的实际,呵呵。扯远了,我们回头看内存管理。

JVM提供了很多类库,封装了很多数据类型和常用工具类,作为自己的基本库来使用,比如java.lang包。举一个最简单的例子,来一句最简单的代码。int i = 5;

在C语言里,这句话申请了几个字节的内存,然后放了个5进去,Java也是这么搞的。只不过,C语言里申请了以后要自己管理,而Java你不用自己烦恼这个事情,虚拟机会帮你处理。它会判断何时需要,何时不需要。由此推开去,更加复杂的业务,比如连接数据库,读取文件,我们要做的只是调用类库而已,内存申请和释放都由虚拟机全盘接管,我们不用动一根手指头。

我们是爽了,虚拟机就头疼了。这么多对象,什么时候该销毁,什么时候该保持,什么时候要检查这些关系呢?在JVM里,这个事情有一个模块来做,也就是我们这片文章的主角,GC,Garbage Collection,垃圾回收。

假设我们是实现GC的程序员,那么我们要做什么呢?首先,负责分配内存,负责控制对象的持有计数,负责销毁内存对象,还得负责内存整理什么的。在Sun制定的JVM规范里,详细描述了GC部分要做的事情,这里就不赘述了,想看的话,请自行Google。

现有的JVM,主流的,分别是HotSpot和JRockit,主要研究对象也是这两个。这篇文章里,我们只研究HotSpot,也就是所谓的Sun JVM。目前阶段,Sun的GC方式主要有CMS和G1两种。考虑到效果和实际应用,这里只介绍CMS。

CMS,全称Concurrent Mark Sweep,是JDK1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求较高的应用,并且预期这部分应用能够承受垃圾回收线程和应用线程共享处理器资源,且应用中存在比较多的长生命周期的对象的应用。CMS是用于对tenured generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。

JVM在程序运行过程当中,会创建大量的对象,这些对象,大部分是短周期的对象,小部分是长周期的对象,对于短周期的对象,需要频繁地进行垃圾回收以保证无用对象尽早被释放掉,对于长周期对象,则不需要频率垃圾回收以确保无谓地垃圾扫描检测。为解决这种矛盾,Sun JVM的内存管理采用分代的策略。

1)年轻代(Young Gen):年轻代主要存放新创建的对象,内存大小相对会比较小,垃圾回收会比较频繁。
年轻代分成1个Eden Space和2个Suvivor Space(命名为A和B)。
当对象在堆创建时,将进入年轻代的Eden Space。垃圾回收器进行垃圾回收时,扫描Eden Space和A Suvivor Space,如果对象仍然存活,则复制到B Suvivor Space,如果B Suvivor Space已经满,则复制到Old Gen。同时,在扫描Suvivor Space时,如果对象已经经过了几次的扫描仍然存活,JVM认为其为一个持久化对象,则将其移到Old Gen。扫描完毕后,JVM将Eden Space和A Suvivor Space清空,然后交换A和B的角色(即下次垃圾回收时会扫描Eden Space和BSuvivor Space。这么做主要是为了减少内存碎片的产生。

我们可以看到:Young Gen垃圾回收时,采用将存活对象复制到到空的Suvivor Space的方式来确保尽量不存在内存碎片,采用空间换时间的方式来加速内存中不再被持有的对象尽快能够得到回收。
2)年老代(Tenured Gen):年老代主要存放JVM认为生命周期比较长的对象(经过几次的Young Gen的垃圾回收后仍然存在),内存大小相对会比较大,垃圾回收也相对没有那么频繁(譬如可能几个小时一次)。年老代主要采用压缩的方式来避免内存碎片(将存活对象移动到内存片的一边,也就是内存整理)。当然,有些垃圾回收器(譬如CMS垃圾回收器)出于效率的原因,可能会不进行压缩。
3)持久代(Perm Gen):持久代主要存放类定义、字节码和静态常量等很少会变更的信息。

http://my.oschina.net/u/175660/blog/351702

时间: 2024-09-30 14:17:59

现代JVM内存管理方法的发展历程,GC的实现及相关设计概述(转)的相关文章

Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收

很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确实很低,一方面,Java语言采用面向对象思想,这也决定了其必然是开发效率高,执行效率低.另一方面,Java语言对程序员做了一个美好的承诺:程序员无需去管理内存,因为JVM有垃圾回收(GC),会去自动进行垃圾回收. 其实不然: 1.垃圾回收并不会按照程序员的要求,随时进行GC. 2.垃圾回收并不会及时

JVM内存管理及垃圾回收

一.JVM内存的构 Java虚拟机会将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法.总体分为下面几个部分: 程序计数器(Program Counter Register).JVM虚拟机栈(JVM Stacks).本地方法栈(Native Method Stacks).堆(Heap).方法区(Method Area) 如下图: 1.程序计数器(Program Counter Register) 这 是一块比较小的内存,不在Ram上

java jvm内存管理/gc策略/参数设置

1. JVM内存管理:深入垃圾收集器与内存分配策略 http://www.iteye.com/topic/802638 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项技术当做Java语言的伴生产物.事实上GC的历史远远比Java来得久远,在1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.当Lisp还在胚胎时期,

JVM内存管理及GC机制

一.概述 JavaGC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.经过这么长时间的发展,javaGC机制已经日臻完善,几乎可以自动的为我们做绝大多数的事情. 虽然java不需要开发人员显示的分配和回收内存,这对开发人员确实降低了不少编程难度,但也可能带来一些副作用: 1. 有可能不知不觉浪费了很多内存 2. JVM花费过

JVM内存管理和垃圾回收机制介绍

http://backend.blog.163.com/blog/static/20229412620128233285220/ 内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实现的掌握是Java开发人员开发出高质量的Java系统的必备条件.最近整理了一些关于JVM内存管理和垃圾回收方面的知识,这里梳理一下,分享给大家,希望能够对Java虚拟机有更深入的了解. 1. JVM内存管理 首先,JVM将内存组织为主内存和工作内存两个部分.主内存中主要包括本地方法区和堆.每个线程都有一个工

JVM内存管理(二)

JVM内存管理 JVM在执行java程序的过程中,会把内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁. 程序计数器 程序计数器:当前线程所执行字节码的行号指示器. 由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器只会执行一条线程中的指令.为了线程切换后能够恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各线程之间计数器

JVM内存管理的机制

1.JVM内存管理的机制 内存空间划分为:Sun JDK在实现时遵照JVM规范,将内存空间划分为堆.JVM方法栈.方法区.本地方法栈.PC寄存器. 堆: 堆用于存储对象实例及数组值,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中对象所占用的内存由GC进行回收,在32位操作系统上最大为2GB,在64位操作系统上则没有限制,其大小可通过-Xms和-Xmx来控制,-Xms为JVM启动时申请的最小Heap内存,默认为物理内存的1/64但小于1GB:-Xmx为JVM可申请的最大He

java基础---JVM内存管理以及内存运行机制学习总结

自己从网上搜资料拼接了一张JVM内存图:如下图所示: 我们思考几个问题: 1.jVM是怎么运行的? 2.JVM运行时内存是怎么分配的? 3.我们写的java代码(类,对象,方法,常量,变量等等)最终存放在哪个区? VM运行时数据区域: 1.程序计数器(program Counter Register):   是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的 方式去实 现),字节码解释器工作时就是通过改

java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)

概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任. 对于Java程序员来说,不需要在为每一个new操作去写配对的delete/free,不容易出现内容泄漏和内存溢出错误,看起来由JVM管理内存一切都很美好.不过,也正是因为Java程序员把内存控制的