[jjzhu学java]之深入理解JVM之垃圾收集器与内存分配策略

简介: 深入理解JVM之垃圾收集器与内存分配策略如何判断对象已经消亡引用计数算法根搜索算法引用深入理解JVM之垃圾收集器与内存分配策略java中对象的创建需要的内存都是在java堆中申请的,所以垃圾收集的区域就是对java堆和方法区的内存区域进行GC。如何判断对象已经消亡垃圾收集器的主要任务就是找出已经“消亡”的对象,将其标记并

深入理解JVM之垃圾收集器与内存分配策略

java中对象的创建需要的内存都是在java堆中申请的,所以垃圾收集的区域就是对java堆和方法区的内存区域进行GC。

如何判断对象已经消亡

垃圾收集器的主要任务就是找出已经“消亡”的对象,将其标记并清除其说用内存的过程,如何判断某个对象已经“消亡”,不同的虚拟机有不同的判断策略

引用计数算法

引用计数(Reference Counting)算法的基本思想就是:给每个对象添加一个引用计数器,每当有一个地方对该对象进行了引用,引用计数器就加1;引用失效后就减1;当引用计数器为0时,就表示没有任何地方引用了该对象,这可以认为该对象已经“消亡”了。
虽然引用计数算法思想简单,效率也很高,但是java虚拟机并没有用到该算法标记“消亡”对象,因为当出现循环引用的时候,表现就不是那么好了。我们可以编写测试代码测试并看GC信息看看java虚拟机到底有没有用该算法。

/** 
* @ClassName: ReferenceCountingGC 
* @Description: 引用计算GC 
* @author 祝佳俊(jjzhu_ncu@163.com)
* @date 2016年10月20日 下午4:57:53 
*  
*/
public class ReferenceCountingGC {
    public Object instance = null;
    private static final int _1MB = 1024 * 1024;
    private byte[] bigSize = new byte[2 * _1MB];
    public static void testGC(){
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB; //互相引用
        objB.instance = objA;
        objA = null;
        objB = null;

        System.gc();
    }
    public static void main(String[] args) {
        testGC();
    }
}

代码示例中,新建了两个对象objA,objB,然后通过objA.instance = objB,objB.instance = objA让他们互相引用,然后将objA、objB都置为空,将会触发GC,我们可以通过-XX:+PrintGCDetails让java虚拟机在发生GC后打印出GC的具体信息,
代码片运行时的VM参数为-Xmx20M -Xms20M -XX:+PrintGCDetails
运行程序,可看到如下打印结果:

[GC [PSYoungGen: 4340K->256K(5952K)] 4340K->256K(19648K), 0.0009373 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System) [PSYoungGen: 256K->0K(5952K)] [PSOldGen: 0K->162K(13696K)] 256K->162K(19648K) [PSPermGen: 3025K->3025K(21248K)], 0.0053905 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 5952K, used 205K [0x00000000ff960000, 0x0000000100000000, 0x0000000100000000)
  eden space 5120K, 4% used [0x00000000ff960000,0x00000000ff993408,0x00000000ffe60000)
  from space 832K, 0% used [0x00000000ffe60000,0x00000000ffe60000,0x00000000fff30000)
  to   space 832K, 0% used [0x00000000fff30000,0x00000000fff30000,0x0000000100000000)
 PSOldGen        total 13696K, used 162K [0x00000000fec00000, 0x00000000ff960000, 0x00000000ff960000)
  object space 13696K, 1% used [0x00000000fec00000,0x00000000fec28910,0x00000000ff960000)
 PSPermGen       total 21248K, used 3043K [0x00000000f9a00000, 0x00000000faec0000, 0x00000000fec00000)
  object space 21248K, 14% used [0x00000000f9a00000,0x00000000f9cf8c28,0x00000000faec0000)

在分析结果前,先对GC的内容先做一个介绍:

1、GC日志的第一行[GC [PSYoungGen说明了在新生代发生了GC(Minor GC),这里也可以看出,当前的HotSpot虚拟机采用的是Parallel Scavenge(PS)垃圾收集器 后面的4340K->256K代表GC前后的新生代内存区域的变化,这里从4340K变到256K,说明虚拟机进行了垃圾回收,后面的(5952K)代表新生代的内存区域大小,4340K->256K(19648K)这里的括号内的19648K代表新生代和年老代的内存大小。之后的0.0009373 secs代表的是GC所用的事件。
2、GC日志的第二行[Full GC (System)表示系统触发的一次Full GC,也就是代码中System.gc();所引起的GC,一次Full GC会对java堆中的所有区域进行GC(新生代、年老代、永久代),所以后面的PSYoungGen(新生代)、PSOldGen(年老代)、PSPermGen(永久带)显示了各区域的GC情况,我们可以看到PSYoungGen: 256K->0K(5952K),新生代经过Full GC后,全被清空了。
3、后面的Heap堆显示了各区域的最终使用情况
从最后的Full GC (System) [PSYoungGen: 256K->0K(5952K)]可以看到,新生代中的内存全被GC了,所以说,HotSpot并没有用引用计数算法来对“消亡”对象进行GC。

根搜索算法

现在一般的垃圾收集器都是用该算法(GC Root Tracing)来判断对象是否“消亡”,该算法的基本思想就是:通过一组称为“GC Roots”的对象作为根节点,然后从这些根节点向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到根节点之间没有任何一条引用链的话,就认为该对象已经“消亡”,如下图所示:

可以作为GC Roots的对象包括:
1. 虚拟机栈(栈帧中的本地变量表)中的引用的对象
2. 方法区中 的类静态属性引用的对象
3. 方法区中的常量引用的对象
4. Native方法引用的对象

引用

任何判断对象是否消亡都是通过引用来判断,引用以前的定义是:如果reference类型的数据中存储的数值代表的是另一块内存区域的起始地址的话,就称这块内存代表一个引用

目录
相关文章
|
12天前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
88 3
|
2月前
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
3月前
|
存储 分布式计算 Java
Java 大视界 -- Java 大数据在智能建筑能耗监测与节能策略制定中的应用(182)
本文探讨了Java大数据技术在智能建筑能耗监测与节能策略制定中的关键应用。通过Hadoop、Spark等技术实现能耗数据的存储、分析与可视化,结合实际案例,展示了Java大数据如何助力建筑行业实现节能减排目标。
|
13天前
|
存储 缓存 NoSQL
工作 10 年!Redis 内存淘汰策略 LRU 和传统 LRU 差异,还傻傻分不清
小富带你深入解析Redis内存淘汰机制:LRU与LFU算法原理、实现方式及核心区别。揭秘Redis为何采用“近似LRU”,LFU如何解决频率老化问题,并结合实际场景教你如何选择合适策略,提升缓存命中率。
146 3
|
1月前
|
缓存 监控 Kubernetes
Java虚拟机内存溢出(Java Heap Space)问题处理方案
综上所述, 解决Java Heap Space溢出需从多角度综合施策; 包括但不限于配置调整、代码审查与优化以及系统设计层面改进; 同样也不能忽视运行期监控与预警设置之重要性; 及早发现潜在风险点并采取相应补救手段至关重要.
199 17
|
3月前
|
存储 人工智能 自然语言处理
AI代理内存消耗过大?9种优化策略对比分析
在AI代理系统中,多代理协作虽能提升整体准确性,但真正决定性能的关键因素之一是**内存管理**。随着对话深度和长度的增加,内存消耗呈指数级增长,主要源于历史上下文、工具调用记录、数据库查询结果等组件的持续积累。本文深入探讨了从基础到高级的九种内存优化技术,涵盖顺序存储、滑动窗口、摘要型内存、基于检索的系统、内存增强变换器、分层优化、图形化记忆网络、压缩整合策略以及类操作系统内存管理。通过统一框架下的代码实现与性能评估,分析了每种技术的适用场景与局限性,为构建高效、可扩展的AI代理系统提供了系统性的优化路径和技术参考。
168 4
AI代理内存消耗过大?9种优化策略对比分析
|
2月前
|
监控 Kubernetes Java
最新技术栈驱动的 Java 绿色计算与性能优化实操指南涵盖内存优化与能效提升实战技巧
本文介绍了基于Java 24+技术栈的绿色计算与性能优化实操指南。主要内容包括:1)JVM调优,如分代ZGC配置和结构化并发优化;2)代码级优化,包括向量API加速数据处理和零拷贝I/O;3)容器化环境优化,如K8s资源匹配和节能模式配置;4)监控分析工具使用。通过实践表明,这些优化能显著提升性能(响应时间降低40-60%)同时降低资源消耗(内存减少30-50%,CPU降低20-40%)和能耗(服务器功耗减少15-35%)。建议采用渐进式优化策略。
134 1
|
2月前
|
存储 监控 算法
Java垃圾回收机制(GC)与内存模型
本文主要讲述JVM的内存模型和基本调优机制。
|
2月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
200 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
|
2月前
|
机器学习/深度学习 监控 安全
解密虚拟化弹性内存:五大核心技术与实施策略
本文深入解析虚拟化环境中实现内存弹性管理的五大核心技术与实施策略。内容涵盖内存架构演进、关键技术原理、性能优化方法及典型问题解决方案,助力提升虚拟机密度与资源利用率。
123 0

热门文章

最新文章