【Java】JVM垃圾回收机制与类加载机制

【Java】JVM垃圾回收机制与类加载机制不同于C++需要编程人员手动释放内存,Java有虚拟机,因此Java不需要程序员主动去释放内存,而是通过虚拟机自身的垃圾回收器(GarbageCollector-GC)来进行对象的回收。Java语言由于有虚拟机的存在,实现了平台无关性,在任意平台都是通过将代码转换为字节码文件,从而在平台下的虚拟机中运行代码的。JVM内存区域分布虚拟机栈:存放每个方法执行时的栈帧,一个方法调用到…

大家好,又见面了,我是你们的朋友全栈君。

不同于C++需要编程人员手动释放内存,Java有虚拟机,因此Java不需要程序员主动去释放内存,而是通过虚拟机自身的垃圾回收器(Garbage Collector-GC)来进行对象的回收。Java语言由于有虚拟机的存在,实现了平台无关性,在任意平台都是通过将代码转换为字节码文件,从而在平台下的虚拟机中运行代码的。

 

JVM内存区域分布

【Java】JVM垃圾回收机制与类加载机制

虚拟机栈:存放每个方法执行时的栈帧,一个方法调用到完成就对应栈帧在虚拟机栈中入栈和出栈的过程。

本地方法栈:和虚拟机栈类似,不过是为Java中native方法服务的。平时所说的“栈内存”指的就是虚拟机栈和本地方法栈的合称。

程序计数器:当前线程执行字节码的行号指示器,字节码解释器工作依赖于它。占用较小的内存空间,不会出现OOM。

堆:即所谓的“堆内存”。JVM所管理最大的一块内存,被所有线程共享。唯一作用就是给对象实例分配内存空间,在分代回收算法中的新生代老年代就在于堆中。

方法区(也称为永久代):不在堆中,被各个线程共享,存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。其中包括常量池。

另:直接内存,不属于JVM内存区域,与NIO联系紧密,不受JVM内存大小限制。

 

JVM垃圾回收机制

  • 何时进行垃圾回收?

GC本质上是一道守护进程(Daemon Thread),不停的检测堆中是否有不可达对象并释放内存,因此GC在何时发生其实我们是无法预测的。GC通过调用对象的finalize()方法来摧毁对象。

  • 回收谁?

GC回收堆中的不可达对象。

不可达对象的判定:根搜索算法。JVM中有一系列设定的GC Roots,当一个对象到任意一个GC Root都没有引用链时,则说明此对象不可达。

注:JVM并不是通过引用计数法来判断不可达对象的,因为这种办法没法解决循环引用的问题。

 

JVM中的垃圾回收算法

1、标记-清除算法

最基础的算法,GC会判断堆中对象是否不可达,如果满足清理条件(查看该对象是否有必要执行finalize()方法,有无必要的标准是该对象有没有被调用过finalize方法或该对象有没有覆盖finalize()方法,因为finalize()只能被调用一次),则给这个对象进行标记,将对象放在F-queue队列。此时除非对象在finalize()方法中重新获得了引用,否则它就会被清除掉。

以下几种算法不过都是对标记清除算法的改进。

2、复制算法

将内存分为大小相等的两块,当对象不可达后并不是及时清理,而是等待正在使用的内存满了之后,将该内存内还存活的对象整体复制到另一块内存中,复制结束后再清理掉原内存块中的所有内容。这种方法的优点是快速,但牺牲了一半的内存。方法的改进版(事实上也是虚拟机的做法)是只在新生代空间使用复制算法,并且由于新生代对象生命周期往往很短,因此又将新生代区域分为Eden和Survivor空间。其中Eden分配的空间又比Survivor大出很多,从而节省内存空间。如果存活对象过多,使得Survivor区也满,那么就会转移Survivor区对象到老年代。

3、标记-整理算法

标记过程与1一样,将1中的清除过程换成了整理,即将内存中存活的对象归拢到一边,使得内存更“紧凑”一些,整理之后将边界之外的对象清理掉。这种算法是为了防止2算法中出现存活率100%的极端情况,那么复制就没有止境了。

4、分代算法

新生代采用2算法,老年代采用1或3算法。这是由他们的特点决定的,新生代注定了其中很多对象生命周期转瞬即逝,因此复制算法移动的存货对象并不是很多。而老年代存活率较高,只能采用1、3来执行,提高效率。

JVM参数相关

  • 可以调整堆内新生代老年代比例
  • 可以调整对象移入老年代的年龄
  • 可以调整堆内存大小
  • 可以设置每个栈大小
  • 可以设置堆内分区大小
  • 可选择垃圾回收方式

JVM类加载机制

双亲委派模型。

类加载器(ClassLoader)用来实现类的加载动作。JVM中只存在两种不同的类加载器:启动类加载器和其他类加载器。

启动类加载器:即Bootstrap ClassLoader。由C++编写,在JVM内部。其他类加载器都由Java编写,在JVM外部,全部继承于抽象类java.lang.ClassLoader。

 

类加载器之间的层次关系,称为双亲委派模型。

顶层为启动类加载器,下边为扩展类加载器,再下为应用程序类加载器,其中包含多种自定义类加载器。

【Java】JVM垃圾回收机制与类加载机制

 

如果一个类加载器收到了加载类的请求,它首先不会自己去加载,而是委派给它的父加载器去执行。层层委派之后,到了顶层由启动类加载器加载,只有当父加载器反馈无法加载此请求,才会让子加载器去加载。这种结构使得Java类型体系中的加载机制清晰准确,不易造成混乱。

有一种双亲委派模型的异常情况,即类似启动类加载器这种基础的类加载器,本应默认为所有类适用的加载器,但由于一些环境下调用SPI(Service Provider Interface),绕过双亲委派模型的层次结构使得父加载器委派子加载器去完成类加载动作。

还有一种情况,即为了实现模块的动态性、热部署,不再使用双亲委派模型,而是使用更加复杂的网状结构。OSGi技术即是类加载器网状结构的一个最佳实践。

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144945.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 二维矩阵中的最大矩形面积–java实现

    二维矩阵中的最大矩形面积–java实现

    2021年9月26日
    43
  • pytorch ocr 数字识别库_pytorch handbook

    pytorch ocr 数字识别库_pytorch handbook实时姿态估计网络:https://github.com/Sierkinhane/AtrousPose简单单人跟踪:https://github.com/Sierkinhane/human_tracker(基于目标检测与特征映射算法)演示视频:https://www.bilibili.com/video/av44360925新写的关于人脸检测算法MTCNN的文章https://……

    2025年10月30日
    5
  • webservice 第三方接口[通俗易懂]

    webservice 第三方接口[通俗易懂]出处:http://www.blogjava.net/amigoxie/archive/2010/12/21/341257.html1.    WebService接口1.1 接口方式说明和优点在笔者的开发生涯中,当作为接口提供商给第三方提供接口时,以及作为客户端去调用第三方提供的接口时,大部分时候都是使用Web Service接口,WebService作为接口使用广

    2022年5月12日
    39
  • BERT模型实战之多文本分类(附源码)

    BERT模型实战之多文本分类(附源码)写在前面BERT模型也出来很久了,之前看了论文学习过它的大致模型(可以参考前些日子写的笔记NLP大杀器BERT模型解读),但是一直有杂七杂八的事拖着没有具体去实现过真实效果如何。今天就趁机来动手写一写实战,顺便复现一下之前的内容。这篇文章的内容还是以比较简单文本分类任务入手,数据集选取的是新浪新闻cnews,包括了[‘体育’,‘财经’,‘房产’,‘家居’,‘教育’,‘科技’,‘时尚’…

    2022年6月10日
    156
  • mac下升级terminal/终端的subversion版本方法

    mac下升级terminal/终端的subversion版本方法

    2021年9月16日
    71
  • android开发笔记之异步ThreadPoolExecutor

    android开发笔记之异步ThreadPoolExecutorandroid异步开发android异步开发,主要有1.Thread+Handler进行异步处理2.继承Thread类和实现Runnable接口3.AsyncTask类4.RxJava5.AsyncQueryHandler但是事实上AsyncTask是有缺点的。syncTaskisdesignedtobeahelperclassaroundThreadandH…

    2022年7月13日
    14

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号