博客信息

关于JVM的一篇文章

0
发布时间:『 2021-04-12 09:11』  博客类别:面试技巧  阅读(79) 评论(0)

对于JVM、GC、类加载,很多人摸不清楚头绪,不知道他们之间的关系。误以为GC和类加载还有JVM区分统称垃圾回收,实则他们包含的东西很多,很细,完整的了解正个JVM的加载过程,就需要全面理解这些东西。

我认为的理解相互关联步骤:

  1. 类的加载过程

  2. 通过类的加载延伸到gc的编译原理

  3. 根据gc得到解决方案并拓展锁知识

  4. 根据这些完全熟悉gc的生态链

下面开始开始简述相关知识。


一.类加载

1.类加载的过程

222


(1)将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个类的java.lang.Class对象,作为方法区类数据的访问入口,这个过程需要类加载器参与。

(2)分为三个阶段:

            1)验证阶段:验证文件的安全性,防止对jvm本身造成危害;

            2)准备阶段:正式为类变量(static变量)分配内存并设置类变量初始值

            3)解析阶段:虚拟机常量池的符号引用替换为字节引用过程

(3)执行类构造器初始化类对象;

  总结:初始化-加载-销毁


2.由类加载过程延伸的问题

(1)类加载器?

       虚拟机提供了3种类加载器:

             启动类加载器:主要加载的是JVM自身需要的类,这个类加载使用C++语言实现的,是虚拟机自身的一部分;

             扩展类加载器:负责加载JAVAHOME路径下的jdk中的一些类库;

             系统类加载器:负责加载CLASSPATH路径下的应用程序。


(2)jvm以什么样的方式加载一个类

       采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象,而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式即把请求交由父类处理,它一种任务委派模式。 那么,一起来理解下双亲委派模式:

image.png

双亲委派:如图,根据自定义类加载器-再到系统类-然后拓展类-最后引导类加载器。如果你在最下层系统类加载器中,编写了一个StringUtil,但是在引导类加载器也有一个相同类,默认只加载系统存在的StringUtil,主要原因是防止修改核心类,保证安全性, 双亲委派模式的好处是避免了一个类会被重复加载。


3.jvm什么时候决定加载一个类?

       1)创建对象就会触发加载;

       2)引用了该类的静态属性、方法都会触发类的加载;

       3)初始化子类也会导致父类被加载;


4.java中创建对象的几种方式?

       1) new对象

       2) 用反射创建对象(代理)

       3) 克隆对象

       4) 序列化


二.JVM

JVM定义:指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。

线程私有区域:程序计数器、Java虚拟机栈、本地方法栈(与线程生命周期一致)

线程共享区域:Java堆、方法区、运行时常量池

jvm主要知道它各个模块与作用即可。(小型独立运行的虚拟机)


三.GC

1.GC本质上就是对JVM内存管理的一个名词(垃圾回收)。

栈:和唯一的一个线程强绑定,线程出现就需要这块内存,线程结束,这块内存就可以回收了,这块内存的分配/回收时机是明确的,就不需要 GC 来操心。

常量池+方法区:首先,这两块内存占比较小,其次,里面的数据很少“失去作用”。回收这块内存性价比不高,也不是重点考虑的。

堆:GC 的重点就是如何管理堆上的内存。堆上的内存是以对象为单位进行管理的,分配与回收的都是一个完整的对象。因此,回收转换成了回收死对象的问题。


2.如何判断对象已死

死对象:没有引用指向的对象。

        1)引用计数法ReferenceCount:无法解决对象的循环引用问题

给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已"死"。 引用计数法实现简单,判定效率也比较高。

        2)可达性分析算法

核心思想: 通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。

 GC Roots的对象包含下面几种: 

       虚拟机栈(栈祯中的本地变量表)中引用的对象

  1. 方法区中的静态属性不回收,所以有引用指向的对象必须活着,常量引用的对象

  2. 常量池中引用指向的对象

如果在GC过程中,可达性分析后对象的引用关系发生了变化,有可能造成对象回收错误,所以通常在GC中,会通知应用线程的执行(STW:Stop The World) 


3.引用分类

  1)强引用:被引用的对象必需活着

  2)弱引用:gc就回收

  3)虚引用:和引用无关,但是回收会通知

  4)软引用:被引用的对象尽可能活着,但是内存紧张可以回收


4.垃圾回收算法

  1)标记清除标出所有需要回收的对象回收。

  2)复制算法(新生代回收算法):把空间分2区域,把使用的对象复制到新区域,便于区分回收。缺点:需要翻倍内存。

  3)标记整理(老年代回收算法):第一阶段标记被引用对象,第二阶段遍历堆,清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。(清除和复制的结合)

  4)分代收集算法:根据对象存活周期分块,分为新生代和老年代。新生代采用复制,老年代采用标记整理

    



对象在Eden区分配

大多数情况下,对象在新生代中 Eden 区分配。当 Eden 区没有足够空间进行分配时,虚拟机将发起一次Minor GC。


看看 Minor GC和Full GC 有什么不同呢?

Minor GC/Young GC:指发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。

Major GC/Full GC:一般会回收老年代 ,年轻代,方法区的垃圾,Major GC的速度一般会比Minor GC的慢10倍以上。


Eden与Survivor区默认8:1:1 大量的对象被分配在eden区,eden区满了后会触发minor gc,可能会有99%以上的对象成为垃圾被回收掉,剩余存活 的对象会被挪到为空的那块survivor区,下一次eden区满了后又会触发minor gc,把eden区和survivor区垃圾对象回 收,把剩余存活的对象一次性挪动到另外一块为空的survivor区,因为新生代的对象都是朝生夕死的,存活时间很短,所 以JVM默认的8:1:1的比例是很合适的,让eden区尽量的大,survivor区够用即可


关键字:   无
博主信息

勿扰
简介:对自己狠一点,社会才会对你好一点!
4年12月
QQ
热门文章
Powered by 勿扰 V2.0 湘ICP备18002237号-2     Copyright © 2016-2023 勿扰个人博客 版权所有