Java基础学习---3、堆、GC(一)

简介: Java基础学习---3、堆、GC(一)

1、堆

1.1 概述

1.1.1 堆空间结构

ba4603fd44a346c7a782fb516ac3c6ca.png

1.1.2 堆空间工作机制

新创建的对象会放在Eden区

当Eden区中已使用的空间达到一定比例,会触发Minor GC

每一次在Minor GC中没有被清理掉的对象就成了幸存者。

幸存者对象会被转移到幸存者区

幸存者区分成from区和to区

from区快满的时候,会将仍然在使用的对象转移到to区

然后from和to这两个指针彼此交换位置

口诀:复制必交换,谁空谁为to

如果一个对象,经历15次GC仍然幸存,那么它将会被转移到老年代

如果幸存者区已经满了,即使某个对象尚不到15次,仍然会被移动到老年代

最终效果:

Eden区主要是生命周期很短的对象来来往往

老年代主要是生命周期很长的对象。例如:IOC容器对象、线程池对象、数据库连接池对象等等。

幸存者区作为两者之间的过度地带

关于永久代

从理论上来说属于堆

从具体实现上来说不属于堆

1.1.3堆、栈、方法区之间关系


8c74bb3965c14df4b806c3116a446a00.png

1.1.4 常驻Web对象存活时间

生产环境下:

ServletContext存活时间:

时间单位:月、年

HttpSession存活时间:

时间单位:分钟、小时

HttpServletRequest存活时间:服务器端接收到请求~服务器提交响应

时间单位:秒或毫秒

HttpServletResponse存活时间:服务器端接收到请求~服务器给客户端返回了响应数据

时间单位:秒或毫秒

2.GC

为什么要有垃圾回收?

  • 线程私有空间:无需由系统来执行GC。因为线程结束,释放自己刚才使用的空间即可,不影响其它线程。
  • 线程共享空间:任何一个线程结束时,都无法确定刚才使用的空间是不是还有别的线程在使用。所以不能因为线程结束而释放空间,必须在系统层面统一垃圾回收。GC的基本原则:
  • 频繁收集新生代
  • 较少收集老年代
  • 基本不动元空间

2.1 标记垃圾对象

垃圾对象的标准:不再被引用的对象。下面这两种方法都是要把这样的对象找出来。

1、引用计数法(不采用)

(1)本意

  • 在对象内部记录被引用次数
  • 被引用一次,计数器+1
  • 引用解除一个,计数器-1
  • 计数器归零则表示该对象变成垃圾

(2)问题

循环引用问题,会导致计数器无法归零。

2、GC Roots可达性分析

核心原理:判断一个对象,是否存在从堆外到堆内的引用

因为我们写Java代码时,是不可能直接访问到堆内对象的,要么是通过方法里面局部变量,要么通过static修饰的常量、类变量。局部变量、类变量、常量这些都在堆外。

3、GC Root对象

GC Root对象:就是作为根节点出发,顺着引用路径一直查找到堆空间内,找到堆空间中的对象。

虚拟机栈(Java Stack栈帧中的局部变量区,也叫局部变量表)中引用的对象

本地方法栈(Native Method Stack)中的局部变量

方法区中的类变量、常量引用的对象(说白了就是用static修饰的成员变量指向的对象)

2.2 垃圾回收算法

1、回收范围

5ce15ef31eca45a5bd525dbea6f863b6.png

JVM在进行GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是指新生代。

minor GC:只针对新生代区域的GC,指发生在新生代的垃圾收集动作。

因为大多数Java对象存活率都不高,所以Minor GC非常频繁,一般回收速度也比较快。

major

对老年代的垃圾回收

Major GC的速度一般会比Minor GC慢10倍以上,STW的时间更长

如果Major GC后,内存还不足,就报OOM了。

full GC:清理范围包括新生代、老年代和方法区,非常慢。

2、GC年龄

新生代的对象每经历一次GC,只要它还活着,GC年龄就会+1.当GC年龄达到15的时候,该对象就会转移到老年代。

对象在新生代的最大GC年龄可以设置:

-XX:MaxTenuringThreshold

从JDK8开始,64位虚拟机的最大GC年龄不能超过15。

2.2.1 基本算法

1、引用计数法(不采用)

优点:

实时性较高,不需要等到内存不够时才回收

垃圾回收时不用挂起整个程序,不影响程序正常运行

缺点:

回收时不移动对象,所以会造成内存碎片问题

不能解决对象间的循环引用问题(致命问题,一票否决)

小结:

正是由于引用计数法不能解决对象间的循环引用问题,所以事实上并没有哪一款JVM产品采用这个机制。

2、标记清除法

它的做法是当堆中的有效内存空间被耗尽时,就会暂停、挂起整个程序(也被称为stop the world),然后进行两项工作,第一项则是标记,第二项则是清除。

标记:标记的过程其实就是从根对象开始变量所以得对象,然后将所有存活的对象标记为可达对象。

清除:清除的过程中将遍历堆中的所有对象,将没有标记的对象全部清除掉。

小结:

优点:实现简单

缺点:

效率低,因为标记和清除两个动作都有遍历所有的对象

垃圾收集后可能会造成大量·的内存碎片

垃圾回收时会造成应用程序暂停

6b2c182e5c2545f3a1405cbfe1c5b68b.png

3、标记压缩法

既然教标记压缩算法,那么它也分为两个阶段,一个时标记(mark),一个时压缩(compact)。所谓压缩就是把存在碎片的空间连起来。

标记压缩算法是在标记清除算法的基础之上,做了优化改进的算法。和标记清除算法一样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是简单的清理未标记的对象,而是将存活的对象移动到内存的一端,然后清理边界以外的垃圾,从而解决了碎片化的问题。

标记:标记的过程其实就是从根对象开始遍历所以对象,然后将所有存活的对象标记为可达的对象。

压缩:移动所以的可达对象到堆内存的同一个区域中,使它们紧凑的排列在一起,从而将所有非可达对象释放出来的空闲内存都集中在一起,通过这样的方式来达到减少内存碎片的目的。

小结

优点:标记压缩算法是对标记清除算法的优化,解决了碎片化的问题

缺点:还是效率问题,在标记清除算法上又多加了一步,效率就更低了

86092f6501ae4d559b3ae57f5e07c8da.png


相关文章
|
29天前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
86 43
Java学习十六—掌握注解:让编程更简单
|
21天前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
14天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
1月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
31 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
22天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
1月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
41 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
1月前
|
存储 算法 Java
带你学习java的数组军队列
带你学习java的数组军队列
35 0
|
1月前
|
Java 大数据 开发工具
java学习——环境准备(1)
java学习——环境准备(1)
42 0
|
Java 算法 搜索推荐
Java实现堆的封装,进行插入,调整,删除堆顶以完成堆排序实例
简介 堆对于排序算法是一个比较常用的数据结构,下面我就使用Java语言来实现这一算法 首先,我们需要知道堆的数据结构的形式,其实就是一个特殊的二叉树。但是这个二叉树有一定的特点,除了是完全二叉树以外,对于最大堆而言,堆顶元素的值是最大的,而且对于堆的每一个子树也是一个小一号的最大堆;同样对于最小堆,性质相反就可以了。
815 0
|
12天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。