java中GC基础知识总结

举报
zhulin1028 发表于 2022/07/01 22:05:19 2022/07/01
890 0 0
【摘要】 目录 1. Java中为什么会有GC机制呢 2. 对于Java的GC哪些内存需要回收 3. Java的GC什么时候回收垃圾 1. Java中为什么会有GC机制呢 安全性考虑;-- for security. 减少内存泄露;-- erase memory leak in some degree. 减少程序员工作量。-...

目录

1. Java中为什么会有GC机制呢

2. 对于Java的GC哪些内存需要回收

3. Java的GC什么时候回收垃圾


1. Java中为什么会有GC机制呢

安全性考虑;-- for security.

减少内存泄露;-- erase memory leak in some degree.

减少程序员工作量。-- Programmers don't worry about memory releasing.

2. 对于Java的GC哪些内存需要回收

内存运行时 JVM 会有一个运行时数据区来管理内存。它主要包括 5 大部分:程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap).

而其中程序计数器、虚拟机栈、本地方法栈是每个线程私有的内存空间,随线程而生,随线程而亡。例如栈中每一个栈帧中分配多少内存基本上在类结构确定是哪个时就已知了,因此这 3 个区域的内存分配和回收都是确定的,无需考虑内存回收的问题。

但方法区和堆就不同了,一个接口的多个实现类需要的内存可能不一样,我们只有在程序运行期间才会知道会创建哪些对象,这部分内存的分配和回收都是动态的,GC 主要关注的是这部分内存。总而言之,GC 主要进行回收的内存是 JVM 中的方法区和堆;

3. Java的GC什么时候回收垃圾

在面试中经常会碰到这样一个问题(事实上笔者也碰到过):如何判断一个对象已经死去?

很容易想到的一个答案是:对一个对象添加引用计数器。每当有地方引用它时,计数器值加 1;当引用失效时,计数器值减 1.而当计数器的值为 0 时这个对象就不会再被使用,判断为已死。是不是简单又直观。然而,很遗憾。这种做法是错误的!为什么是错的呢?事实上,用引用计数法确实在大部分情况下是一个不错的解决方案,而在实际的应用中       也有不少案例,但它却无法解决对象之间的循环引用问题。比如对象 A 中有一个字段指向了对象 B,而对象 B 中也有一个字段指向了对象 A,而事实上他们俩都不再使用,但计数器的值永远都不可能为 0,也就不会被回收,然后就发生了内存泄露。

所以,正确的做法应该是怎样呢?

在 Java,C#等语言中,比较主流的判定一个对象已死的方法是:可达性分析(Reachability Analysis).

所有生成的对象都是一个称为"GC Roots"的根的子树。从 GC Roots 开始向下搜索,搜索所经过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链可以到达时,就称这个对象是不可达的(不可引用的), 也就是可以被 GC 回收了。

无论是引用计数器还是可达性分析,判定对象是否存活都与引用有关!那么,如何定义对象的引用呢?

我们希望给出这样一类描述:当内存空间还够时,能够保存在内存中;如果进行了垃圾回收之后内存空间仍旧非常紧张,则可以抛弃这些对象。所以根据不同的需求,给出如下四种引用,根据引用类型的不同,GC 回收时也会有不同的操作:

1)强引用(Strong Reference):Object obj = new Object();只要强引用还存在,GC 永远不会回收掉被引用的对象。

2)软引用(Soft Reference):描述一些还有用但非必需的对象。在系统将会发生内存溢出之前,会把这些对象列入回收范围进行二次回收(即系统将会发生内存溢出了,才会对他们进行回收。)

弱引用(Weak Reference):程度比软引用还要弱一些。这些对象只能生存到下次 GC 之前。当 GC 工作时,无论内存是否足够都会将其回收(即只要进行 GC,就会对他们进行回收。)

虚引用(Phantom Reference):一个对象是否存在虚引用,完全不会对其生存时间构成影响。关于方法区中需要回收的是一些废弃的常量和无用的类。

(1)废弃的常量的回收。这里看引用计数就可以了。没有对象引用该常量就可以放心的回收了。

(2)无用的类的回收。什么是无用的类呢?

A.该类所有的实例都已经被回收。也就是 Java 堆中不存在该类的任何实例;

B.加载该类的 ClassLoader 已经被回收;

C.该类对应的 java.lang.Class 对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。总而言之:

对于堆中的对象,主要用可达性分析判断一个对象是否还存在引用,如果该对象没有任何引用就应该被回收。而根据我们实际对引用的不同需求,又分成了 4 中引用,每种引用的回收机制也是不同的。

对于方法区中的常量和类,当一个常量没有任何对象引用它,它就可以被回收了。而对于类,如果可以判定它为无用类,就可以被回收了。

文章来源: zhulin1028.blog.csdn.net,作者:zhulin1028,版权归原作者所有,如需转载,请联系作者。

原文链接:zhulin1028.blog.csdn.net/article/details/121478424

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。