jvm垃圾回收之类加载机制

简介: jvm垃圾回收之类加载机制

类的生命周期:



image.png


1.加载:.class文件(二进制数据)——>读取到内存——>数据放进方法区——>堆中创建对应Class对象——>并提供访问方法区的接口


2.验证、准备、解析:


(1)验证主要是用来检查class文件格式是否正确


(2)准备阶段:为类变量分配内存


public static int test = 100; //准备阶段,test=0; public int test2 = 100;


public static final int test3 = 100; //准备阶段,test3=100


(3)解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,一般不关注。


3.初始化:到了初始化阶段,用户定义的 Java 程序代码才真正开始执行。


Java程序对类的使用方式可分为两种:主动使用与被动使用。一般来说只有当对类的首次主动使用的时候才会导致类的初始化,所以主动使用又叫做类加载过程中“初始化”开始的时机。


类的主动使用包括以下六种:


1.创建类的实例,也就是new的方式


2.访问某个类或接口的静态变量,或者对该静态变量赋值(被final修饰除外,会放入常量池)


3.调用类的静态方法


4.反射(如 Class.forName(“java.lang.String”))


5.初始化某个类的子类,则其父类也会被初始化


6.Java虚拟机启动时被标明为启动类的类,还有就是Main方法的类会首先被初始化


最后注意一点对于静态字段,只有直接定义这个字段的类才会被初始化(执行静态代码块)。


类加载器



image.png


双亲委派模型:



image.png


双亲委派机制:



1.当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成;


2.当 ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成;


3.如果 BootStrapClassLoader加载失败(例如在 $JAVA_HOME/jre/lib里未查找到该class), 会使用 ExtClassLoader来尝试加载;


4.若ExtClassLoader也加载失败,则会使用 AppClassLoader来加载,如果 AppClassLoader也加载失败,则会报出异常 ClassNotFoundException。


类层次关系



image.png


自定义一个类加载器:



@Data
public class MyClassloader extends ClassLoader {
    private String root;
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name);
        if (classData == null) {
            throw new ClassNotFoundException();
        } else {
            return defineClass(name, classData, 0, classData.length);
        }
    }
    /**
     * 获取类的二进制数据
     *
     * @param className
     * @return
     */
    private byte[] loadClassData(String className) {
        String fileName = root + File.separatorChar
                + className.replace('.', File.separatorChar) + ".class";
        try {
            InputStream ins = new FileInputStream(fileName);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int bufferSize = 1024;
            byte[] buffer = new byte[bufferSize];
            int length = 0;
            while ((length = ins.read(buffer)) != -1) {
                baos.write(buffer, 0, length);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) throws Exception {
        MyClassloader classLoader = new MyClassloader();
        classLoader.setRoot("C:\\Users\\Administrator\\Desktop\\javhl\\app-starter\\target\\classes");
        Class<?> testClass = null;
//            testClass = classLoader.loadClass("com.javhl.course.clazzloader.FatherSonClassTest");
        testClass = classLoader.findClass("com.javhl.course.clazzloader.FatherSonClassTest");
        Object object = testClass.newInstance();
        System.out.println(object.getClass().getClassLoader());
    }
}


JDK8之后的内存区域



image.png


内存结构图



image.png


元空间(Metaspace):



1.从JDK8开始,永久代(PermGen)的概念被废弃掉了,取而代之的是一个称为Metaspace的存储空间。Metaspace使用的是本地内存,而不是堆内存,也就是说在默认情况下Metaspace的大小只与本地内存大小有关。当然你也可以通过以下的几个参数对Metaspace进行控制:


2.-XX:MetaspaceSize=N:这个参数是初始化的Metaspace大小,该值越大触发Metaspace GC的时机就越晚。随着GC的到来,虚拟机会根据实际情况调控Metaspace的大小,可能增加上线也可能降低。在默认情况下,这个值大小根据不同的平台在12M到20M浮动。使用java - XX:+PrintFlagsInitial命令查看本机的初始化参数,-XX:Metaspacesize为21810376B(大约20.8M)。


3.-XX:MaxMetaspaceSize=N:这个参数用于限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序。在本机上该参数的默认值为4294967295B(大约4096MB)。


4.-XX:MinMetaspaceFreeRatio=N:当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比小于这个参数,那么虚拟机将增长Metaspace的大小。在本机该参数的默认值为40,也就是40%。设置该参数可以控制Metaspace的增长的速度,太小的值会导致Metaspace增长的缓慢,Metaspace的使用逐渐趋于饱和,可能会影响之后类的加载。而太大的值会导致Metaspace增长的过快,浪费内存。


5.-XX:MaxMetasaceFreeRatio=N:当进行过Metaspace GC之后, 会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放Metaspace的部分空间。在本机该参数的默认值为70,也就是70%。


哪部分内存区域需要回收?



1.程序计数器、虚拟机栈、本地方法栈是线程私有的,随线程而生;随线程而灭。栈中的栈帧随着方法的进入和退出执行出栈和入栈操作,每一个栈帧分配多少内存基本上是在类结构确定下来时就已经是已知的; 因此,这几个区域的分配和回收都具备确定性。方法结束或者线程结束时,内存自然就跟着回收了。


2.而Java堆和方法区则不一样,一个接口中多个实现类需要的内存可能不一样,一个方法中多个分支需要的内存也可能不一样,只有在程序运行期间才知道创建哪些对象,这部分内存的分配和回收都是动态的。垃圾收集器关注的是这部分内存。


引用计数法(无法解决循环引用问题)



image.png


可达性分析算法



image.png


Java引用类型:



  1. 强引用。Java中默认声明的就是强引用,比如:只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了

Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收obj = null; //手动置null


2.软引用( java.lang.ref.SoftReference )。软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。


3.弱引用(java.lang.ref.WeakReference )。弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。如:JDK中的ThreadLocalMap的Key就是弱引用。


4.虚引用( java.lang.ref.PhantomReference)。虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收。虚引用必须和引用队列(ReferenceQueue)一起使用。当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去。程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。



目录
相关文章
|
2天前
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
65 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
1月前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
45 3
|
1月前
|
算法 Java
谈谈HotSpot JVM 中的不同垃圾回收器
【10月更文挑战第5天】理解 HotSpot JVM 中的不同垃圾回收器(如 CMS、G1 和 ZGC)的区别,需要深入了解它们的设计原理、工作方式和应用场景。以下是对这三个垃圾回收器的简要概述以及一个示例 Java 程序,虽然示例程序本身不能直接展示垃圾回收器的内部机制,但可以帮助观察不同垃圾回收器的行为。
25 1
|
1月前
|
存储 Java C语言
【JVM】类加载机制
【JVM】类加载机制
21 1
|
2月前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
112 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
2月前
|
Arthas Java 测试技术
JVM —— 类加载器的分类,双亲委派机制
类加载器的分类,双亲委派机制:启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器;JDK8及之前的版本,JDK9之后的版本;什么是双亲委派模型,双亲委派模型的作用,如何打破双亲委派机制
JVM —— 类加载器的分类,双亲委派机制
|
1月前
|
存储 Java PHP
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
60 0
|
2月前
|
缓存 Java Python
python垃圾回收&缓存机制
python垃圾回收&缓存机制