Java面试总结之Full GC

本文深入解析Java垃圾回收机制(GC),介绍GC的基本概念,包括分代收集算法、JVM内存结构,以及GC的触发条件。文章详细阐述了堆内存的管理,年轻代、老年代和持久代的区别,以及GC如何在不同条件下触发。此外,还探讨了GC回收的内容和具体过程,包括各种回收算法和常用垃圾回收器。

一、gc的定义

GC,即就是Java垃圾回收机制。目前主流的JVM(HotSpot)采用的是分代收集算法。与C++不同的是,Java采用的是类似于树形结构的可达性分析法来判断对象是否还存在引用。即:从gcroot开始,把所有可以搜索得到的对象标记为存活对象。
二、gc的基础知识准备

要了解GC的触发条件,就要先对 JVM的内存结构有一定的了解。我们通常所说的GC主要是针对运行的数据区的。作为程序员要关注的区域主要有5块,分别是方法区(Method Area),Java栈(Java stack),本地方法栈(Native Method Stack),堆(Heap),程序计数器(Program Counter Register)。实际jvm在管理内存的时候,比这个分的更细致,只不过做应用程序开发,我们只需要关注这5块就可以了。
在这里插入图片描述
堆(Heap),是Jvm管理的内存中最大的一块。程序的主要数据也都是存放在堆内存中的,这一块区域被所有的线程所共享,通常出现线程安全问题的一般都是这个区域的数据出现的问题。

方法区(Method Area),与Heap一样,也是各个线程共享的内存域,这块区域主要是用来存储类加载器加载的类信息,常量,静态变量,通俗的讲就是编译后的class文件信息。

Jvm栈,与程序计数器一样,它是每个线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

本地方法栈(Native Method Stacks),本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

程序计数器,个人感觉的他就是为多线程准备的,程序计数器是每个线程独有的,所以是线程安全的。它主要用于记录每个线程的执行情况。

通常我们所说的gc主要是针对java heap这块区域的。下面来了解一下heap区。
在这里插入图片描述
从图中我们可以看出jvm heap区域是分代的,分为年轻代,老年代和持久代。 JVM的堆区对象分配的一般规则:

  1. 对象优先在Eden区分配

  2. 大对象直接进入老年代(-XX:PretenureSizeThreshold=3145728 这个参数来定义多大的对象直接进入老年代)

  3. 长期存活的对象将进入老年代(在JDK8中测试,-XX:MaxTenuringThreshold=1的阀值设定根本没用)

  4. 动态对象年龄判定(虚拟机并不会永远地要求对象的年龄都必须达到MaxTenuringThreshold才能晋升老年代,如果Survivor空间中相同年龄的所有对象的大小总和大于Survivor的一半,年龄大于或等于该年龄的对象就可以直接进入老年代)

  5. 空间分配担保

  6. 只要老年代的连续空间大于(新生代所有对象的总大小或者历次晋升的平均大小)就会进行minor GC,否则会进行full GC

三、gc的触发条件

充分了解了jvm的内存结构之后,下面我们就来说说什么情况下会触发gc。触发full gc的情况主要有这几种:

(1)System.gc()方法的调用。此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI(Java远程方法调用)调用System.gc。

(2)旧生代空间不足。旧生代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出错误:java.lang.OutOfMemoryError: Java heap space 。为避免以上两种状况引起的FullGC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

(3)Permanet Generation空间满了。Permanet Generation中存放的为一些class的信息等,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出错误信息:java.lang.OutOfMemoryError: PermGen space 。为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存。如果发现统计数据说之前Minor GC的平均晋升大小比目前old gen剩余的空间大,则不会触发Minor GC而是转为触发full GC。

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

四、gc回收的内容

知道了gc触发的条件之后,我们就能知道gc主要回收什么了?gc的主要作用是回收堆中的对象。通过可达性分析一个对象的引用是否存在,如果不存在,就可以被回收了。

四、gc的具体过程

那么,gc的是如何实现的,这个主要看是用的哪一种回收算法以及用的什么垃圾回收集了。回收算法主要有:

  • 标记-清除
  • 复制算法
  • 标记-整理(Mark-Compat)算法
  • 分代收集(Generational Collection)算法
  • 这里针对不同的代,可以使用一些相对合适的算法。

新生代中,每次垃圾收集时都有大批对象死去,只有少量存活,就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集;

老年代中,其存活率较高、没有额外空间对它进行分配担保,就应该使用“标记-整理”或“标记-清理”算法进行回收。

常用的垃圾回收器:

  • Serial收集器
  • ParNew收集器
  • Parallel Scavenge收集器
  • CMS(Concurrent Mark Sweep)收集器
  • G1(Garbage First)收集器(从JDK1.7 Update 14之后的HotSpot虚拟机正式提供了商用的G1收集器)

关于垃圾回收器的使用,这里也有一个组合建议共大家参考:
在这里插入图片描述

### 2025 Java 面试题汇总及答案解析 #### 关于 JVM Full GC 排查 当遇到频繁的Full GC情况时,可以通过多种方式来诊断和解决问题。首先应当启用垃圾回收日志记录功能,这有助于理解GC行为模式以及识别潜在性能瓶颈。通过分析这些日志数据,可以定位到具体引起Full GC的原因并采取相应措施优化应用程序或调整JVM参数设置[^1]。 #### 字符串转整数的方法 在Java中,`Integer.parseInt(String s)` 是一种常用的方式用于把字符串形式表示的数值转换成为对应的int类型的值;另外还有 `Integer.valueOf(String s)` 方法也可以达到同样的效果,不过它返回的是一个 Integer 对象而不是基本的数据类型 int 。如果输入不是有效的数字格式,则会抛出 NumberFormatException 异常[^3]。 #### 同步与异步的区别 同步意味着调用方会在等待服务端处理请求完成之后才会继续执行后续逻辑;而异步则允许客户端发送指令给服务器后立即去做其他事情,在得到响应之前不必停滞不前。例如,在多线程环境中使用 synchronized 关键字修饰的方法就是典型的同步操作,因为它会让多个线程排队依次访问共享资源;相反地,采用回调函数机制或者Future接口实现的任务提交属于非阻塞式的异步通信模式[^10]。 ```java // 同步方法示例 public static synchronized void syncMethod() { System.out.println(Thread.currentThread().getName()+" is executing"); } // 异步方法示例 (基于CompletableFuture) public static CompletableFuture<Void> asyncMethod(){ return CompletableFuture.runAsync(() -> { try{ Thread.sleep(100); System.out.println("Asynchronous operation completed."); }catch(Exception e){ throw new RuntimeException(e.getMessage()); } }); } ``` #### Spring Cloud 核心组件概述 Spring Cloud 提供了一系列微服务体系下的开发工具包,其中包括但不限于 Eureka(服务发现)、Hystrix(熔断器)、Zuul/ Gateway (API网关)、Config Server(配置中心)等重要模块。它们共同构成了支持分布式系统的基础设施层面上的服务治理框架[^112]。 #### Hibernate 和 MyBatis 的比较 两者都是持久化技术解决方案,但是设计理念有所差异:Hibernate 更加面向对象设计原则,强调映射关系定义自动化程度高;相比之下,MyBatis 则更贴近SQL语句本身的操作,给予开发者更大的灵活性控制查询过程中的细节部分。因此选择哪一个取决于项目需求和个人偏好[^7]。 #### JDK 版本特性更新趋势预测 随着每一年度的新版本发布计划推进,预计至2025年为止将会持续引入更多现代化特性和改进现有功能集。比如增强Lambda表达式的支持范围、进一步简化并发编程模型等等。同时也会不断加强对于安全性的重视力度,确保平台能够应对日益复杂的网络环境挑战[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值