聊聊Java的GC机制

GC:垃圾回收(Garbage Collection),在计算机领域就是指当一个计算机上的动态存储器(内存空间)不再需要时,就应该予以释放,以让出存储器,便于他用。这种存储器的资源管理,称为垃圾回收。有一些语言是没有垃圾回收机制的,像C、C++,如果需要释放无用变量内存空间就由自己来处理。而其他的一些语言如Java、C#都支持垃圾回收器,Java虚拟机(JVM)或.NET CLR发现内存资源紧张的时候,就会自动地去清理无用对象(没有被引用到的对象)所占用的内存空间。而我们今天主要讲Java中的GC。上面说到JVM会自动清理无用的对象,那么我们就有了疑问:

  • JVM清理的是哪一块的对象?

  • 哪些对象会被清理,为什么清理A而不清理B?

  • JVM又是如何清理的?

这三个问题将分别对应接下来的3节一一解答。/   JVM内存结构简单介绍   /我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。在《Java虚拟机规范(Java SE 8)》

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4

中描述了JVM运行时内存区域结构如下:

以上是Java虚拟机规范,不同的虚拟机实现可能会各有不同,但是一般会遵守规范。

  • 方法区:存储已被虚拟机加载的类信息、常量、静态变量等

  • 堆:堆是Java 虚拟机所管理的内存中最大的一块。唯一目的就是存放对象实例。在虚拟机栈中存放的只是引用,而引用指向的是堆中的对象。GC主要作用的区域。

  • 虚拟机栈:局部变量表、操作数栈等。虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法返回地址等信息。

  • 本地方法栈:与虚拟机栈类似,是为native方法提供服务的。

  • 程序计数器:记录当前线程执行的方法执行到了第几行。如果线程正在执行的是一个Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。

/   可达性分析与GC Roots   /


可达性分析Java中通过可达性分析法来确定某个对象是不是“垃圾”。该方法的基本思想是通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。注意其本质是通过找出所有活对象来把其余空间认定为“无用”,而不是找出所有死掉的对象并回收它们占用的空间。如下图,当object5、6、7不存在到GC Roots的引用时,即不可到达GC Roots,则判定他们是不可达的。

GC Roots对于哪些对象可以被当成GC Roots网上有很多种说法,有的不够权威、有的不够全面。最终找到了一份eclipse的官方文档,里面有如下的介绍:Garbage Collection Roots

https://help.eclipse.org/2019-09/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Fconcepts%2Fgcroots.html&resultof=%22%67%61%72%62%61%67%65%22%20%22%67%61%72%62%61%67%22%20

(自己翻译了一下,如有不准确的地方,请指出)A garbage collection root is an object that is accessible from outside the heap. The following reasons make an object a GC root:

System Class (被boostrap 或者系统类加载器加载的系统类)

Class loaded by bootstrap/system class loader. For example, everything from the rt.jar like java.util.

JNI Local( 一些用户定义jni 代码或者jvm的内部代码局部变量)

Local variable in native code, such as user defined JNI code or JVM internal code.

JNI Global( jni 代码中的全局变量)

Global variable in native code, such as user defined JNI code or JVM internal code.

Thread Block(被阻塞的线程引用的对象)

Object referred to from a currently active thread block.

Thread (正在运行的线程)

A started, but not stopped, thread.

Busy Monitor(正在等待的线程)

Everything that has called wait() or notify() or that is synchronized.For example, by calling synchronized(Object) or by entering a synchronized method. Static method means class, non-static method means object.

Java Local(仍然在线程的栈中的方法的传入参数或方法内部创建的对象)

Local variable.For example, input parameters or locally created objects of methods that are still in the stack of a thread.

Native Stack(本地方法栈中输入或输出参数,例如,用于文件/网络I/O的方法或反射的参数。****)

In or out parameters in native code, such as user defined JNI code or JVM internal code. This is often the case as many methods have native parts and the objects handled as method parameters become GC roots.For example, parameters used for file/network I/O methods or reflection.**Finalizable(在回收队列中的对象)

**An object which is in a queue awaiting its finalizer to be run.Unfinalized(覆盖了finalize方法但是还没有被放入回收队列中的对象)

An object which has a finalize method, but has not been finalized and is not yet on the finalizer queue.**Unreachable(一个从任何其他根无法访问的对象,但由Memory Analyzer Tool 标记为根,以便该对象可以包含在分析中)

An object which is unreachable from any other root, but has been marked as a root by MAT to retain objects which otherwise would not be included in the analysis.Java Stack FrameA Java stack frame, holding local variables.Only generated when the dump is parsed with the preference set to treat Java stack frames as objects.

Unknown**An object of unknown root type. Some dumps, such as IBM Portable Heap Dump files, do not have root information. For these dumps the MAT parser marks objects which are have no inbound references or are unreachable from any other root as roots of this type. This ensures that MAT retains all the objects in the dump.复制代码简单总结下就是:

  • 由系统类加载器(system class loader)加载的对象

  • 活着的线程,包含处于等待或阻塞的线程

  • 当前被调用的方法(Java方法、native方法)的一些参数/局部变量

  • 方法区中静态变量、常量引用的对象

  • Held by JVM - JVM由于特殊目的为GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。
    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

感受:

其实我投简历的时候,都不太敢投递阿里。因为在阿里一面前已经过了字节的三次面试,投阿里的简历一直没被捞,所以以为简历就挂了。

特别感谢一面的面试官捞了我,给了我机会,同时也认可我的努力和态度。对比我的面经和其他大佬的面经,自己真的是运气好。别人8成实力,我可能8成运气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。

也祝愿各位同学,都能找到自己心动的offer。

分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档

拿到字节跳动offer后,简历被阿里捞了起来,二面迎来了P9"盘问"

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
学习路线),都已经整理成了电子文档

[外链图片转存中…(img-qrkHqHEz-1712987176869)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值