`
joe_zhjiang
  • 浏览: 155644 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java 虚拟机优化之垃圾回收机制

    博客分类:
  • j2ee
阅读更多
Java性能优化之垃圾回收(GC)

事先声明一下:虽说SUN公司已经被Oracle吞并了,但是出于习惯,同时也为了偷懒节省打字,以下仍然称之为SUN公司。

JVM的内 存
在Java虚拟机规范中(具体章节请看http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#1732 ),提及了如下几种类型的内存空间:
栈内存(Stack):每个线程私有的。
堆 内存(Heap):所有线程公用的。
方法区 (MethodArea):有点像以前常说的“进程代码段”,这里面存放了每个加载类的反射信息、类函 数的代码、编译时常量等信息。
原生方法栈 (NativeMethodStack):主要用于JNI中的原生代码,平时很少涉及。

关 于栈内存(Stack)和堆内存(Heap),已经在上次的帖子中扫盲过了,大伙儿应该有点印象。由于今天咱们要讨论的“垃圾回收”话题,主要是和堆内存 (Heap)有关。其它的几个玩意儿不是今天讨论的重点。等以后有空了,或许可以单独聊一下。

垃圾回收机制简介
其实Java虚 拟 机规范中并未规定垃圾回收的相关细节。垃圾回收具体该怎么搞,完全取决于各个JVM的设计者。所以,不同的JVM之间,GC的行为可能会有一定的差异。下 面咱拿SUN官方的JVM来简单介绍一下GC的机制。
啥时候进行垃圾回收?
一般情况下,当JVM发现堆内存比较紧张、不太够用时,它就 会 着手进行垃圾回收工作。但是大伙儿要认清这样一个残酷的事实:JVM进行GC的时间点是无法准确预知的。因为GC启动的时刻会受到各种运行环境因素的影 响,随机性太大。
虽说咱们无法准确预知,但如果你想知道每次垃圾回收执行的情况,还是蛮方便的。可以通过JVM的命令行参数 “-XX:+PrintGC”把相关信息打印出来。
另外,调用System.gc()只是建议JVM进行GC。至于JVM到底会不会做,那就不好 说啦。通常不建议自己手动调用System.gc(),还是让JVM自行决定比较好。另外,使用JVM命令行参数 “-XX:+DisableExplicitGC”可以让System.gc()不起作用。
谁来负责垃圾回收?
一般情况下,JVM会有一 个或多个专门的垃圾回收线程,由它们负责清理回收垃圾内存。
如何发现垃圾对象?
垃圾回收线程会从“根集(RootSet)”开始进行对 象 引用的遍历。所谓的“根集”,就是正在运行的线程中,可以访问的引用变量的集合(比如所有线程当前函数的参数和局部变量、当前类的成员变量等等)。垃圾回 收线程先找出被根集直接引用的所有对象(不妨叫集合1),然后再找出被集合1直接引用的所有对象(不妨叫集合2),然后再找出被集合2直接引用的所有对 象......如此循环往复,直到把能遍历到的对象都遍历完。
凡是从根集通过上述遍历可以到达的对象,都称为可达对象或有效对象;反之,则是不 可 达对象或失效对象(也就是垃圾)。
如何清理/回收垃圾?
通过上述阶段,就把垃圾对象都找出来。然后垃圾回收线程会进行相应的清理和回 收工 作,包括:把垃圾内存重新变为可用内存、进行内存的整理以消除内存碎片、等等。这个过程会涉及到若干算法,有兴趣的同学可以参见“这里”。限于篇幅,咱就 不深入聊了。
分代
早期的JVM是不采用分代技术的,所有被GC管 理的对象都存放在同一个堆里面。这么做的缺点比较明显:每次进行GC都要 遍历所有对象,开销很大。其实大部分的对象生命周期都很短(短命对象),只有少数对象比较长寿;在这些短命对象中,又只有少数对象占用的内存空间大;其它 大量的短命对象都属于小对象(很符合二八原理)。
有鉴于此,从JDK1.2之后,JVM开始使用分代的垃圾回收 (GenerationalGarbageCollection)。JVM把GC相关的内存分为年老代(Tenured)和年轻代(Nursery)、持 久代(Permanent,对应于JVM规范的方法区)。大部分对象在刚创建时,都位于年轻代。如果某对象经历了几轮GC还活着(大龄对象),就把它移到 年老代。另外,如果某个对象在创建时比较大,可能就直接被丢到年老代。经过这种策略,使得年轻代总是保存那些短命的小对象。在空间尺寸上,年轻代相对较 小,而年老代相对较大。
因为有了分代技术,JVM的GC也相应分为两种:主要收集(MajorCollection)和次要收集 (MinorCollection)。主要收集同时清理年老代和年轻代,因此开销很大,不常进行;次要收集仅仅清理年轻代,开销很小,经常进行。

GC 对性能会有啥影响?
刚才介绍了GC的大致原理,那GC对性能会造成哪些影响捏?主要有如下几个方面:
造成当前运行线程的停顿
早 期 的GC比较弱智。在它工作期间,所有其它的线程都被暂停(以免影响垃圾回收工作)。等到GC干完活,其它线程再继续运行。所以,早期JDK的GC一旦开始 工作,整个程序就会陷入假死状态,失去各种响应。
经过这些年的技术改进(包括采用分代技术),从JDK1.4开始,GC已经比较精明了。在它干 活 期间,只是偶尔暂停一下其它线程的运行(从长时间假死变为暂时性休克)。
遍历对象引用的开销
试想如果JVM中的对象很多,那遍历完所 有可 达对象肯定是比较费劲的工作,这个开销可不小。
清理和回收垃圾的开销
遍历完对象引用之后,对垃圾的清理和回收也有较大的开销。这部 分开销 可能包括复制内存块、更新对象引用等等。

几种收集器
两个性能指标
因为今天聊的是性能的话题,必然会提到衡量GC 性能的两 个重要指标:吞吐量(Throughput)和停顿时间(PauseTime)。吞吐量这个词不是很直观,解释一下:就是JVM不用于GC的时间占总时间 的比率。吞吐量是越大越好,停顿时间是越小越好。
不同的应用程序对这两个指标的关注点不一样(后面具体会说),也就是所谓的“众口难调”。很多 JVM厂商为了迎合“众口”,不得不提供多种几种垃圾收集器供使用者选择。不同的收集器,采用的收集策略是不一样的,下面具体介绍。
串行收集器 (SerialCollector)
使用命令行选项“-XX:+UseSerialGC”指定。
这种收集器是最传统的收集器。它使用单 线 程进行垃圾回收,对于单CPU机器比较合适。另外,小型应用或者对上述两个指标没有特殊要求的,可以使用串行收集器。
并行收集器 (ParallelThroughputCollector)
顾名思义,这种收集器使用多个线程进行垃圾回收以达到高吞吐量。垃圾回收线程的数量 通过命令行选项“-XX:ParallelGCThreads=n”指定。可以设置该数值以便充分利用多CPU/多核。
当使用命令行选项 “-XX:+UseParallelGC”时:它会针对年轻代使用多个垃圾回收线程,对年老代依然使用单个线程的串行方式。此选项最早在JDK1.5引 入。
当使用命令行选项“-XX:+UseParallelOldGC”时:它针对年轻代和年老代都使用多个垃圾回收线程的方式。不过此选项从 JDK1.6才开始引入。
并发收集器(ConcurrentLowPauseCollector)
使用命令行选项 “-XX:+UseConcMarkSweepGC”指定。
这种收集器优先保证程序的响应。它会尽量让垃圾回收线程和应用自身的线程同时运行,从 而降低停顿时间。此选项从JDK1.4.1开始支持。
增量收集器(IncrementalCollector)
自从JDK1.4.2以 来,SUN官方就停止维护该收集器了。所以俺就节省点口水,不多说了。

如何降低GC的影响?
尽量减少堆内存的使用
由于 GC是针对存储在堆内存的对象进行的。咱们如果在程序中减少引用对象的分配(也就相应降低堆内存分配),那对于提高GC的性能是很有帮助滴。上次“字符串 过滤实战”的帖子给出了一个例子,示范了如何通过降低堆内存的分配次数来提升性能。

设置合适的堆内存大小
JVM的堆内存是有讲 究 的,不能太大也不能太小。如果堆内存太小,JVM老是感觉内存不够用,可能会导致频繁进行垃圾回收,影响了性能;如果堆内存太大,以至于操作系统的大部分 物理内存都被JVM自个儿霸占了,那可能会影响其它应用程序甚至操作系统本身的性能。
另外,年轻代的大小(或者说年轻代与年老代的比值)对于 GC 的性能也有明显影响。如果年轻代太小,可能导致次要收集很频繁;如果年轻代太大,导致次要收集的停顿很明显。
JVM提供了若干和堆内存大小 相关的 命令行选项,具体如下:
------------------------------
-Xms设置初始堆内存
-Xmx 设置最大 堆内存
-Xmn设置年轻代的大小
-XX:NewRatio=n设置年轻代与年老代的比例为“n”
-XX:NewSize=n 设置 年轻代大小为“n”
------------------------------
一般情况下,JVM的默认参数值已经够用。所以 没事儿 别轻易动用上述选项。如果你非调整不可,一定要做深入的性能对比测试,保证调整后的性能确实优于默认参数值。

吞吐量和停顿的取舍
前 面提到了不同应用的众口难调。常见的口味有两种:(1)看重吞吐量,对停顿时间无所谓;(2)侧重于停顿时间。
对于某些在后台的、单纯运算密集 型 的应用,属于第一种。比如某些科学计算的应用。这时候建议使用并行收集器。
对于涉及用户UI交互的、实时性要求比较高、程序需要快速响应的, 属于 第二种。比如某些桌面游戏、某些电信交换系统。这时候建议使用并发收集器。

相关的参考资料
GC调优资料
SUN官方 提供了 若干关于JVM垃圾回收调优的说明文档,JDK1.4.2请看“这里”;JDK1.5 请看“这里”;JDK1.6请看“这里”。
JVM命令行选项 说明
这是SUN公司内的某个有心人整理的各种命令行参数大全,在 “这里”。包括有每个参数所适用的JDK版本。
虚拟机规范
“这里 ”是SUN官方的JVM规范。


转自:http://blog.sina.com.cn/s/blog_6d003f3f0100lmkn.html
分享到:
评论

相关推荐

    java虚拟机知识点整理

    自己看书整理的 java虚拟机精品知识点 java内存区域与内存溢出处理 虚拟机栈和本地方法栈区别 对象定位访问 垃圾收集器GC管理 虚拟机GC垃圾回收收集算法(内存回收方法论) 虚拟机GC垃圾回收收集器(内存回收具体实现...

    Java虚拟机内存优化实践

    众所周知,Java是从C++的基础上发展而来的,而C++程序的很大的一个问题是内存泄露难以解决,尽管Java的JVM有一套自己的垃圾回收机制来回收内存,在许多情况下并不需要java程序开发人员操太多的心,但也是存在泄露...

    Java虚拟机

    这本书的内容是帮你全面了解java虚拟机,本书第1版两年内印刷近10次,98%以上的评论全部为5星级的好评,是整个Java图书领域公认的经典著作和超级畅销书,繁体版在台湾也十分受欢迎。第2版在第1版的基础上做了很大的...

    Java垃圾回收算法的简易模拟实现.zip

    健壮性与高性能:Java通过垃圾回收机制确保内存的有效管理,同时也能通过JIT编译器优化来提升运行时性能。 标准库丰富:Java拥有庞大的类库,如Java SE(Java Standard Edition)包含基础API,用于开发通用应用...

    Android垃圾回收机制及程序优化System.gc

     Java语言建立了垃圾收集机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽,以及不恰当的内存释放所造成的...

    Java_Card虚拟机的研究与优化_杨富彪.caj

    在垃圾回收方面,分析了系统存储管理机制,针对语言的面向对象特性, 设计了系统的对象管理机制。在对比经典垃圾回收算法的基础上,设计了基于分代思 想的垃圾回收算法,其中复制过程通过使用基于的缓冲事务技术来...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    第2章 Java内存区域与内存溢出异常 / 24 2.1 概述 / 24 2.2 运行时数据区域 / 25 2.2.1 程序计数器 / 25 2.2.2 Java虚拟机栈 / 26 2.2.3 本地方法栈 / 27 2.2.4 Java堆 / 27 2.2.5 方法区 / 28 2.2.6 运行...

    深入解析ANDROID虚拟机

    本书十三个章节,分别讲解了android系统基础知识,android系统的结构和核心框架,Java虚拟机和Dalvik虚拟机的知识,实现程序编译和调试,Dalvik的运作流程,DEX优化和安全管理,Android虚拟机生命周期的管理和内存...

    Java八股文的面试题

    垃圾回收(GC): Java通过垃圾回收机制自动管理内存,开发者无需手动释放对象占用的内存。常见的垃圾回收算法包括标记-清除、复制、标记-整理等。 Java集合框架(JCF): Java集合框架提供了一套性能优化的接口和类,...

    详细讲解了jvm在java中应用

    主要包含:JVM概述,内存结构讲解,对象实例化,垃圾回收,类的加载,程序编译,代码的优化,性能监控与调优. JVM:全称 Java Virtual Machine,一个虚拟计算机,Java 程序的运行环境(Java二...自动的内存管理,垃圾回收机制.

    从虚拟机视角谈Java应用性能优化

    本文从Java虚拟机的角度,特别是垃圾回收机制来剖析了Java应用程序设计需要注意的方面,并总结出了几条非常容易被忽视的设计、编写代码的原则和习惯。最后通过实例来介绍几种主要的JavaProfiler工具对我们进行开发和...

    Java进阶教程解密JVM视频教程

    * 在垃圾回收章节,不仅会介绍垃圾回收算法、分代垃圾回收机制,还会重点介绍 G1 垃圾回收器,辨析 Full GC 发生条件,jdk8以来对垃圾回收的优化,以及垃圾回收的调优法则。 * 在字节码与类加载技术章节,会从一个 ...

    系统性能 系统调优 垃圾回收 企业培训PPT

    为什么J2EE应用程序性能慢? 了解系统限制和设定调优目标 建立性能调优策略 决定调优时机 Java虚拟机内核分析 Java内存泄漏分析 J2EE性能分析 如何优化循环、多分支和递归 ...Java垃圾回收机制分析

    jvm的资源整理

    解释了java虚拟机的内部结构和运行机制,帮助我们优化java虚拟机,该资源包括内存管理,垃圾回收机制

    Java 虚拟机面试题全面解析(干货)

    Java 虚拟机面试题全面解析,《深入理解Java虚拟机》干货版,自己总结,希望能够帮助大家,免费下载~什么是类加载机制? 虚拟机和物理机的区别是什么? 运行时栈帧结构 Java方法调用 什么是方法调用? Java的方法调用,...

    java最新高薪面试题库.docx

    什么是Java虚拟机(JVM)?它如何工作? 什么是垃圾回收?Java中的垃圾回收是如何实现的? Java中的锁机制有哪些?它们有什么区别? 什么是线程安全?在Java中如何实现线程安全? 什么是继承?Java中的继承有哪些...

    免费分享 Java面试笔记 面试八股文 计算机网络基础

    JVM(Java虚拟机):Java内存管理详解、垃圾回收机制、垃圾回收器等;MySQL:基础知识、存储引擎、日志、SQL优化、数据索引、锁、事务、高可用实现等;Spring:IOC、AOP、声明式事务、MVC等;Redis:持久化过程、高...

    Notes:This is a learning note | Java基础,JVM,源码,大数据,面经

    Notes 我的笔记: 知识不总结,就会被大脑当垃圾清理 ...优化垃圾回收机制 Apache的MaxClients参数详解及其在Tomcat执行FullGC时的影响 JavaEE 浅析Web容器 计算机网络 UDP&TCP DB MySQL索引背后的数据结构

    java 进阶之路.zip

    健壮性与高性能:Java通过垃圾回收机制确保内存的有效管理,同时也能通过JIT编译器优化来提升运行时性能。 标准库丰富:Java拥有庞大的类库,如Java SE(Java Standard Edition)包含基础API,用于开发通用应用...

Global site tag (gtag.js) - Google Analytics