java gc

新生代老生代参考http://www.cnblogs.com/E-star/p/5556188.html

垃圾回收算法参考http://blog.youkuaiyun.com/java2000_wl/article/details/8022293

优化参考http://www.importnew.com/author/wangxiaojie 

面向GC编程http://www.importnew.com/11372.html

Java 堆内存http://www.blogjava.net/fancydeepin/archive/2013/09/29/jvm_heep.html

面试GC问答https://www.zhihu.com/question/35164211

 

一、算法

1.引用计数法:一个对象被引用计数器加一,取消引用计数器减一,引用计数器为0才能被回收。优点:简单。缺点:不能解决循环引用的问题,比如A引用B,B引用A,但是这两个对象没有被其他任何对象引用,属于垃圾对象,却不能回收;每次引用都会附件一个加减法,影响性能。

引用计数的方法由于存在显著的缺点,实际上并未被JVM所使用。

 

2.标记清除法:分为两个阶段:标记阶段和清除阶段。标记阶段通过根节点标记所有可达对象,清除阶段清除所有不可达对象。缺点:因为清除不可达对象之后剩余的内存不连续,会产生大量内存碎片,不利于大对象的分配。由于无法找到足够的连续内存,不得不触发另一次GC。

可以做根节点的对象:

虚拟机栈(栈帧中的本地变量表)中的引用的对象

方法区中的类静态属性引用的对象

方法区中的常量引用的对象

本地方法栈中JNI(Native方法)的引用对象

 

3.复制算法:将内存空间分成相同的两块,每次只是用其中的一块,垃圾回收时,将正在使用的内存中的存活对象复制到另外一块空间,然后清除正在使用的内存空间中的所有对象,这种回收算法适用于新生代垃圾回收。优点:垃圾回收对象比较多时需要复制的对象很少,性能较好;不会存在内存碎片。缺点:将系统内存折半。 

 

4.标记压缩算法:是一种老年代回收算法,在标记清除的基础上做了一些优化,首先从根节点开始标记所有不可达的对象,然后将所有可达的对象移动到内存的一端,最后清除所有不可达的对象。优点:不用将内存分为两块;不会产生内存碎片。

 

分代算法:新生代使用复制算法,老生代使用标记清除算法或者标记压缩算法。几乎所有的垃圾回收期都区分新生代和老生带。

 

分区算法:将整个堆空间分成很多个连续的不同的小空间,每个小空间独立使用,独立回收。为了更好的控制gc停顿时间,可以根据目标停顿时间合理地回收若干个小区间,而不是整个堆空间,从而减少gc停顿时间。

 

二、新生代young generation(执行minor gc 复制算法)和老年代old generation(执行major gc或叫full gc标记清除算法)

1.为什么要分代?

总有一些对象是长期使用的,如果每次GC都扫描他们,然后发现无法回收,这样效率就很差。所以就把对象增加了一个年龄属性,这样如果每次GC都回收不掉他们,他们的年龄就增加1,慢慢地就变成老年人了。达到一定年龄后,就要分区了。老年人会离开新生代区域,进入老年代区域。这样常规的GC只扫描新生代区域,处于老年代区域的对象就不会被频繁地扫描了。

80%的对象都是朝生夕死,对于负载不高的应用,可能数月都不会发生FullGC。

 

2.新生代再细分,有三个区域:Eden区,即伊甸园区。还有2个Survivor区,即幸存者区,分别叫from和to。from和to这两块就是复制算法中提到的两块内存,它们互相复制来复制去,互相换着当from和to.当然其中有一个肯定是空的。当eden满时,minorgc开始,Eden区也会执行复制算法,把所有存活对象全部复制到to区域。from区域的对象会根据年龄决定去向,达到要求的就去老年代,没达到要求的也会进入to区域。然后,Eden和from区都会被清空。当to区域也被塞满时,所有对象都会被复制到老年区。

一个对象的一辈子:我是一个普通的Java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后被回收。

新生代98%的对象都是朝生夕死,虚拟机默认eden和survivor大小比例是8;1,也就是每次只有10%的内存空间是作为to区域被浪费,而不是传统复制算法中所说的浪费一半内存。

 

三、面向GC编程优化

1.减少创建对象的数量,比如使用StringBuilder代替string

2.老年代的GC很耗时,要减少进入老年代的对象数量。比如对象池,因为对象长期存活,会晋升到老年代,影响GC效率。另外对象池通常涉及并发访问,处理同步带来的开销也很大。而重新创建一个对象的开销,可能比这两者都要小。

3.在一个非常大的方法体内,对于较大的对象,将其引用置为null,某种程度可以帮助GC。但大部分情况下这种行为意义不大。

4.一些基于数组的数据结构,例如StringBuilder、StringBuffer、ArrayList、HashMap等等,在扩容的时候都需要做ArrayCopy,对于不断增长的结构来说,经过若干次扩容,会存在大量无用的老数组,而回收这些数组的压力,全都会加在GC身上。这些容器的构造函数中通常都有一个可以指定大小的参数,如果对于某些大小可以预估的容器,建议加上这个参数。

5.尽可能缩小对象的作用域,即生命周期。如果可以在方法内声明的局部变量,就不要声明为实例变量。除非你的对象是单例的或不变的,否则尽可能少地声明static变量。

03-28
<think>好的,用户想了解Java的垃圾回收机制以及性能调优。我需要先整理一下已有的引用内容,然后根据这些信息构建一个清晰的回答结构。 首先,查看用户提供的引用内容。引用1提到了Full GC和Concurrent Garbage Collection,引用2介绍了G1 GC作为CMS的替代品,引用3和4是用户的学习经历和一些基础概念。我需要确保回答涵盖垃圾回收的基本原理、不同收集器的类型以及调优方法。 接下来,需要确定回答的结构。可能分为几个部分:垃圾回收的基本概念、常见的垃圾回收器(如Serial、Parallel、CMS、G1)、性能调优的方法,以及相关问题。这样用户能逐步理解。 然后,要注意用户提到的系统级指令,比如使用正确的中文回答,数学公式用$...$,独立公式用$$...$$。不过在这个问题中可能数学公式不多,但如果有涉及算法复杂度的地方需要正确应用,比如时间复杂度O(n)之类的。 还要生成相关问题,放在最后。问题需要Java GC相关,可能涉及不同收集器的比较、调优参数、监控工具等。 需要确保引用的正确使用。比如在提到Full GC时引用[^1],G1 GC时引用[^2]。用户提供的引用3和4可能作为补充,但可能内容较为基础,可以适当引用。 可能遗漏的点是具体的调优参数示例,比如-Xmx、-XX:+UseG1GC等,这些需要包含在调优方法中。此外,监控工具如jstat、GC日志分析也是调优的重要部分,需要提到。 还要注意避免过于技术化的术语,保持解释清晰易懂,符合用户可能的中级水平。同时,确保每个部分的信息准确,比如G1 GC的特点,CMS的缺点等。 最后,检查是否符合格式要求:使用中文,引用标识自然添加,代码块(如果有的话)正确使用语法,分点回答结构清晰。生成的相关问题需要有意义,能够引导用户进一步学习。 总结,回答结构大致如下: 1. 垃圾回收机制概述 2. 主要垃圾回收器类型及特点(包括Serial、Parallel、CMS、G1) 3. 性能调优方法(参数调整、监控工具、避免Full GC等) 4. 相关问题列表 在写作过程中,确保每个部分的信息准确,正确引用提供的资料,并自然融入回答中。</think># Java垃圾回收机制性能调优指南 ## 一、垃圾回收机制基础 Java垃圾回收(Garbage Collection, GC)通过自动内存管理实现对象生命周期控制。核心原理是识别不再被引用的对象并释放其内存空间。JVM内存区域划分包括: - 新生代(Young Generation):存放新创建对象,分为Eden区和两个Survivor区 - 老年代(Old Generation):长期存活对象存储区 - 元空间(Metaspace):类元数据存储区(替代永久代) 触发GC的条件包括内存分配失败或显式调用`System.gc()`[^4]。 ## 二、主流垃圾回收器对比 | 回收器类型 | 工作模式 | 适用场景 | 特点 | |-------------------|------------------|--------------------------|-------------------------------| | Serial GC | 单线程STW | 客户端应用 | 简单低延迟,吞吐量低 | | Parallel GC | 多线程STW | 吞吐量优先 | 默认回收器,高吞吐量 | | CMS GC | 并发标记清除 | 低延迟场景 | 减少停顿时间,内存碎片问题| | G1 GC | 分区并发回收 | 大内存低延迟 | 可预测停顿,吞吐量优化 | | ZGC/Shenandoah | 超低延迟 | 超大堆内存 | 亚毫秒级停顿 | *注:STW(Stop-The-World)指暂停所有应用线程* ## 三、性能调优方法 ### 3.1 参数调优 ```bash # 基础配置示例 -Xmx4g -Xms4g # 堆内存上下限 -XX:+UseG1GC # 启用G1收集器 -XX:MaxGCPauseMillis=200 # 目标最大停顿时间 -XX:ParallelGCThreads=4 # 并行线程数 ``` ### 3.2 监控工具 - `jstat -gcutil <pid>`:实时GC统计 - `jmap -histo:live <pid>`:堆内存直方图 - VisualVM/GCViewer:可视化分析GC日志 ### 3.3 优化策略 1. **避免Full GC**:通过`-XX:+DisableExplicitGC`禁止显式GC调用 2. **对象分配优化**: - 减少大对象直接进入老年代 - 使用对象池复用实例 3. **GC日志分析**: ```bash -XX:+PrintGCDetails -Xloggc:/path/to/gc.log ``` ### 3.4 G1调优专项 $$ \text{Region大小} = \min(\text{堆大小}/2048, 32\text{MB}) $$ 调整`-XX:G1HeapRegionSize`可优化内存利用率 ## 四、典型问题解决方案 **场景1:频繁Full GC** - 检查内存泄漏(MAT工具分析堆转储) - 增大老年代空间或调整晋升阈值 **场景2:长时间GC停顿** - 切换低延迟收集器(G1/ZGC) - 调整`-XX:InitiatingHeapOccupancyPercent`触发阈值 **场景3:Metaspace溢出** - 增加`-XX:MaxMetaspaceSize` - 检查类加载器泄漏
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值