`
sunshine_1985
  • 浏览: 11182 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

深入理解JVM—gc相关

    博客分类:
  • JVM
 
阅读更多

 

        深入理解JVM—gc相关

周四听了毕玄的JVM分享,对于JVM的相关知识, 有了初步的了解,然后根据现场笔记整理形成以下这篇blog

内存管理

    在所有的语言中, 一般是实现了以下两种内存管理的方式之一。

第一种是以c/c++为典型代表的,是需要程序员显示的管理内存,如cmalloc /free  c++new delete。优点非常明显,就是程序员对所有的内存具有完全的控制权,和那些语言层面实现了内存管理的语言相比,效率很高。但是缺点也很明显,就是一不小心,很容易内存泄露, 学习成本较高, 特别是新手,很容易出错。

第二种是以后出现的众多高级语言,例如java python c#等等, 这些语言都不需要主动去管理内存,而是语言层面已经帮你完成了这部分功能,帮你管理内存,对于新手来说,也不容易写出太差的代码。但是同样缺点也很明显,就是你不能很明确的控制什么时候回收内存块。

内存分配和内存的回收是JVMgc主要需要完成的事情, 我们只有通过详细的了解gc相关的触发机制,才可以写出更加建壮的程序。

 

java的内存区域

                                                 

如上图所示, Java内存区域,可以分成以上3个部分。

方法栈: 线程创建时产生,并在方法执行过程中, 一直存在于堆栈中, 在方法中调用新的方法, 那么新的方法栈一样也会被压入堆栈。在方法帧上又保存了方法执行过程中的局部对象和操作数栈。

方法区:存放类的元数据常量。

堆:所有通过new生成的对象都放在这个区域,并通过一个指针指向对应的对象。

Native Memory 这部分也是堆,一般是通过jni之类的c代码存放对象的地方,而不是通过Java尽心管理。

 

2.1内存区的具体划分

sunjdk上, 一般会分成两个区域,如下图所示,一块是新生代 new Generation ,一个是旧生代 old Generation), 在新生代又分成了Eden,还有一般是一样大小的S0 S1两个可以看成是交换区的部分。 通常对于新生代的回收称为minor GC 或者young GC ,而对于旧生代的回收称为old GC

 

 

 




sun jdk GC方式

对于GC 无论是使用还是调优, 最关键是知道到底是什么时候触发的。

sunsdk提供了三种GC。分别是串行, 并行和并发。

3.1 串行

串行是最古老的垃圾回收方式,是client默认的垃圾回收方式(貌似sdk根据几核还有多少内存来判断是client或者是server 虽然现在来看其实不是很靠谱)。缺点是由于使用的是单线程, GC过程比较慢, 没有充分发挥现在的多核多内存的硬件优势。

gc的方式

YGC: Parallel Scavenge(PS)

FGC: Parallel MSC(PSOld),Parallel Compacting(ParOld)

内存回收的时机

YGC的时机:

edn空间不足

FGC的时机:

1.old空间不足;

2.perm空间不足;

3.显示调用System.gc() ,包括RMI等的定时触发;

4.YGC时的悲观策略;

5.dump live的内存信息时(jmap –dump:live)

YGC 触发时机,相当的显而易见,就是eden空间不足, 这时候就肯定会触发ygc

对于FGC的触发时机, old空间不足, perm的空间不足, 调用system.gc()这几个都比较显而易见,就是在这种情况下, 一般都会触发GC

最复杂的是所谓的悲观策略,它触发的机制是在首先会计算之前晋升的平均大小,也就是从新生代,通过ygc变成新生代的平均大小,然后如果旧生代剩余的空间小于晋升大小,那么就会触发一次FullGCsdk考虑的策略是, 从平均和长远的情况来看,下次晋升空间不够的可能性非常大, 与其等到那时候在fullGC 不如悲观的认为下次肯定会触发FullGC 直接先执行一次FullGC。而且从实际使用过程中来看, 也达到了比较稳定的效果。

 

YGC完成的动作

1,将edenfrom中的引用次数为0的对象清除

2,将eden+from中的存活对象复制to

3,如果to放不下或者存活次数超过Tenuring Threshold 那么将会晋升到old

1from to 实际上就是old区中默认相等的两块区域,同时两块区域的使用是互换,没有固定的from to

2 Tenuring Threshold 是一个对象在new中存活,并经历YGC的次数,而且这个次数是动态调整的。

FGC完成的动作

1,如果配置CollectGen0First 将会先执行YGC

2,清空heap中所有的引用为0的对象,以及卸载的所有classLoader

3,单线程完成,全过程应用暂停

       3.2并行

所谓的并行就是多线程同时进行GC,这个是在server默认使用的模式。优点是高效, 主要是相对的串行来说, 充分利用了服务器多核多内存的特点,充分利用所有硬件资源,进行GC 因此相对串行速度快也就是是必然的了。缺点是,如果堆(heap)比较大, 那么暂停的时间可能会比较长,这是现在java语言发展到当今最大的悲剧,没有很好的跟上硬件的发展速度, 当今好的服务器都是几十G的内存,GC一次可能会时间较长, 这对于online的应用是完全无法忍受的。

一触发机制:

YGC 和串行一样。

FGC 和串行基本一样,最大的不同是悲观策略在YGC YGC后会检查两次。

YGC完成的动作是:

基本动作一样, 主要的区别是使用多线程同时gc

另外YGC之后, 会重新计算Edenfrom的大小

FGC完成的动作:

默认ScavengeBeforeFullGC 的参数 会先触发YGC

其他操作基本一样清空没有引用的对象, 卸载class信息

MSC:进行压缩

Compacting进行部分压缩

3.3并发

所谓的并发,就是和之前的串行和并行都需要相对长的暂停时间相比, 并发只需要很短的应用暂停时间,相对来说, 比较时候对延时要求比较高的应用,但是现在的并发并不是很成熟, 存在着一些bug还没有完全fix。并发的优点是:暂停时间短, 延时小。并发的缺点 内存碎片多,在Old区的内存分配的效率很低, 而且由于和应用同时进行, 会出现和应用抢cpu的现象, 导致应用的响应变慢,从而影响用户体验。同时用于没有充分利用硬件资源, 包括内存cpu 所以整个回收的过程会比较久。

一内存回收的时机

YGC 触发时机:

和其他垃圾回收机制一样, 都是eden的空间不足

CMSGC触发时机

oldGC达到一定的使用率的时候,就必须进行FGC,因为这个GC过程中,是不暂停,如果等到空间不足才GC,会导致内存分配失败,而应用无法正常运行 这个比例值可以通过参数进行设置。

Hotspot自己估计是否需要触发CMSGC

显式调用了System.gc()

FGC 触发的时机

   FGC触发的时机是CMSGC失败之后,就会调用GC 并且是调用串行的GC。这样就会非常悲剧,时间很长, 而使用串行的原因是, 并发是继承自串行, 使用了同一套接口,调用比较容易, 而并行是后来重新写的,无法直接使用。

二触发的动作

YGC触发动作

和串行一样, 只是使用了多线程

CMSGC触发动作

1.oldGen达到一定的比例之后就清除所有没有引用的对象

2.perm gen 达到一定比例之后,就清除classload所加载的信息

FGC触发动作

如果并发的GC失败, 会引发一次串行的GC

GC调优

4.1GC调优模式

GC调优, 主要有以下以下衡量尺度, 包括分配内存,GC的频率, GC导致应用暂停的时间 ,应用的响应时间和QPS System load/cpu/IO 等等。

GC调优是一个很看经验的一个大工程。因此就有很多的经验值在里面,

1 对于32位, JVM必须建议控制在2G以下。

2 对于64位, 最好开启指针压缩的选项-XX:+UseCompressedOOPS

3 根据应用的需求, 选择合适的垃圾收集器

4 计算出可能存活的对象数量,并进行相应的设置。

4.2GC的主要模式以及对应的解决方案

降低FGC的频率

      1,很明显增大old

       2,降低从new->old的晋升频率。

二降低FGC的暂停时间

1 .减小Heap

2 .换成CMS 

3.升级CPU(据说最靠谱)

三降低FGC的频率

1 增大新生代

四降低FGC的暂停时间

1减少新生代,可能造成频繁FGC

2升级CPU

4.3写出GC友好的代码

1.尽量减少使用autobox 因为在Java在将原始对类型变成对象的过程中, 需要new一个新的对象过程中,在某些时候,可能会使用大量堆的内存造成内存溢出。

2.合理控制动态增长的数据结构的大小,很多时候内存的超出错误(OOM)都是这些动态数据结构造成, 他给我们带来方便的同时, 也同样带来了不可控制性。

3.合理使用reference

4.不要使用Finalizers来回收资源,据写sdk的人说,Finalizers并不能保证一定会被执行,在某些特殊的时刻,可能会被跳过,这样很容易导致内存泄漏。

sun jdk 内存管理的实现

5.1内存管理的方法

对于java sdk的内存管理来说, 主要需要完成的功能就是对内存的管理, 从空间的申请到释放的过程。

在所有的语言中,内存空间的分配和回收, 主要有以下两种做法。

1对于已经释放的空间使用一个freelist的链表进行保存

优点是:效率高

缺点:空间浪费, 形成碎片

2 通过移动合并, 形成连续的内存空间

优点:内存的使用率较高 

缺点:  移动内存需要时间, 而且需要更新指针

5.2GC的主要算法

GC算法, 需要完成的主要目标是找到垃圾内存块,并进行回收。主要有以下几种经典算法。

一引用计数

这是最老的GC算法, 它具有以下几个明显的缺点, 首先他需要额外的空间, 然后存在一个最主要的问题是无法解决循环引用。

Tracing – Mark-Sweep

需要使用一定的策略遍历所有的对象, 然后进行标记, 之后将没有标记的进行回收。

缺点:随着heap的增大, GC的时间会增长很快

优点:可以清除所有的垃圾

Tracing – Mark-Compact

在标志的基础上,进行移动,使内存块连续。

缺点: 移动需要时间, 需要更新指针

优点,内存使用率高

copying

所谓的复制,就是在遍历过程中 将所有有引用的复制到另外一个分区, 然后剩下的就是没有引用的内存块, 直接对整个内存块进行回收就可以了。 其实就是上面提到的新生代的fromto

优点: 没有垃圾碎片,

缺点: 需要更新指针, 浪费了一块空闲的内存

 

以上这篇日志,都是在分享上听到的或者PPT上的再加上一些我自己的一些理解,再次感谢毕玄这次分享,如果有错,欢迎指正。

1
4
分享到:
评论
2 楼 san_yun 2012-02-06  
引用

4.2GC的主要模式以及对应的解决方案
一 降低FGC的频率 :


应该是 降低YGC的频率 吧?
1 楼 laier903 2011-07-25  
学到不少,谢谢分享~

相关推荐

    深入理解JVM&G1; GC

    《深入理解JVM & G1 GC》一书深入剖析了Java虚拟机(JVM)的工作原理,特别是针对垃圾收集器(GC)中的G1(Garbage-First)算法进行了详尽的探讨。JVM是Java程序运行的基础,它负责解析、编译、执行Java代码,并管理...

    深入理解JVM&G1GC

    资源名称:深入理解JVM & G1 GC内容简介:G1 GC提出了不确定性Region,每个空闲Region不是为某个固定年代准备的,它是灵活的,需求驱动的,所以G1 GC代表了先进性。《深入理解JVM & G1 GC》主要为学习Java语言的...

    深入理解JVM & G1 GC

    《深入理解JVM & G1 GC》这篇文章和相关压缩包文件主要聚焦于Java虚拟机(JVM)的内存管理,特别是垃圾收集器(GC)的优化,特别是G1(Garbage-First)垃圾收集器的深度解析。下面将详细阐述JVM、GC的基本概念,...

    JVM GC原理深入学习.pdf

    同时,为了能更深入理解与之相关的知识点,本文特地编写了“第二章 基础知识”,详细的讲解与GC学习相关的JVM架构、JVM选项、Object内存布局、指针压缩等内容,以便读者能更加清晰的理解GC原理的底层逻辑。

    圣思园张龙 深入理解jvm

    根据提供的文件信息,“圣思园张龙 深入理解jvm”,我们可以推断出这份资料主要关注于Java虚拟机(JVM)的深入理解和实践应用。JVM是Java开发环境中非常核心的一个组成部分,它不仅为Java程序提供了运行时环境,还负责...

    深入理解JVM & G1 GC.rar

    G1 GC提出了不确定性Region,每个空闲Region不是为某个固定年代准备的,它是灵活的,需求驱动的,所以G1 GC代表了先进性。本书主要为学习Java语言的学生、初级程序员提供GC的使用参考建议及经验,着重介绍了G1 GC ...

    JVM 完整深入解析.pdf

    局部变量表存储了方法中使用的局部变量,它们的生命周期与方法的调用和返回严格相关。 #### 本地方法栈 本地方法栈的作用与虚拟机栈相似,区别在于它服务于虚拟机使用到的本地方法(native方法)。Java虚拟机规范并...

    基于周志明老师的《深入理解JVM虚拟机》整理的JVM思维导图

    JVM是每个想深入学习Java必须要了解的,周志明老师的《深入理解JVM虚拟机》对JVM进行了系统且全面的讲解,我已经看过很多遍这本书了。说实话,我觉得这本书对于1-2年Java开发经验的来说都是很难看下去的,因为我就是...

    深入理解JVM内存结构及运行原理全套视频加资料.txt

    2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...

    深入理解 JVM 机制

    深入理解JVM虚拟机机制是Java开发者必备的技能之一。Java技术的核心组成部分包括Java编程语言、Java类文件格式、Java虚拟机(JVM)和Java应用程序接口(Java API)。Java的平台无关性得益于JVM,它在不同操作系统和...

    jvm和gc详解及调优

    《JVM和GC详解及调优》是一本深入解析Java虚拟机(JVM)和垃圾收集(Garbage Collection,简称GC)的专业...对于团队负责人或系统架构师而言,理解JVM和GC调优也是必不可少的技能,有助于提升整个系统的稳定性和效率。

    jvm gc

    理解JVM的GC对于优化Java应用程序性能至关重要。 首先,我们需要了解JVM内存的几个主要区域:堆(Heap)、栈(Stack)、方法区(Method Area)、程序计数器(PC Register)和本地方法栈(Native Method Stack)。GC...

    深入理解jvm视频资源

    深入理解JVM对于优化程序性能、解决内存问题以及提高整体开发能力至关重要。本资源包提供了关于JVM性能调优、内存模型和虚拟机原理的深入学习材料,帮助开发者更全面地掌握这一核心技能。 1. **JVM性能调优**:性能...

    深入理解JVM内存结构及运行原理全套视频加资料

    2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...

    深入理解JVM性能调优和内存模型,垃圾回收,虚拟机原理,经典视频教程

    《深入理解JVM性能调优和内存模型,垃圾回收,虚拟机原理,经典视频教程》是一套详尽的教育资源,旨在帮助Java开发者深入探索Java虚拟机(JVM)的内部工作机制,提升性能优化的能力。本教程共包含110讲,内容丰富,适合...

    深入理解Java虚拟机JVM高级特性与最佳实践1

    《深入理解Java虚拟机JVM高级特性与最佳实践》一书,正是为解决这一需求而生。 本书的作者周志明站在前人的基础上,对JVM进行了全面而深入的解读,不仅覆盖了JVM的基础概念,而且深入探讨了JVM的高级特性,让读者...

    hpjmeter jvm gc监控工具

    通过HPjmeter,开发者和运维人员能够深入理解JVM的行为,分析和优化应用程序性能,预防因内存管理不当导致的问题。同时,它还可以生成报告,便于分析历史数据,发现趋势和模式,为长期性能优化提供依据。总的来说,...

    深入理解jvm源码

    《深入理解Java虚拟机》是Java开发者深入了解JVM(Java Virtual Machine)的必备书籍,尤其对于想要提升技术深度、优化程序性能的工程师来说,更是不可或缺的参考资料。这本书的第二版全面覆盖了JVM的最新发展,包括...

    java应用JVM的GC频率观察方法

    总的来说,理解并监控Java应用的JVM GC频率是保障系统稳定性、性能和可用性的必要步骤。在开发、测试以及生产环境中,应结合使用不同的工具和参数来确保GC行为在可接受范围内,防止因内存管理不当导致的服务中断。...

    JVM规范与深入理解

    深入理解JVM对于开发高性能、稳定的Java应用至关重要。理解内存模型可以帮助我们避免内存溢出,选择合适的垃圾收集器可以优化应用程序的运行效率。同时,熟悉JVM的类加载机制有助于我们进行模块化设计和热部署。此外...

Global site tag (gtag.js) - Google Analytics