我是靠谱客的博主 心灵美夕阳,最近开发中收集的这篇文章主要介绍jvm学习笔记,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一从java.exe开始类加载运行过程
1.Java com.danny.common.Test01.class
2.windows系统下java.exe会调用底层的jvm.dll文件创建java虚拟机
3.创建一个引导类加载器的实例
4.调用java代码创建JVM启动器实例sum.mic.Launcher,该类由引导类加载器负责加载并创建其他类加载器
5.sun.mic.Launcher.getLauncher() 获取运行类自己的加载器ClassLoader
6.调用loadClass 加载要运行的类Test01,classLoader.loadClass(“com.danny.common.Test01”)
7.加载完成后,会执行Test01的main方法入口
8.Test01.main()
9.java程序运行结束
10.jvm销毁

二、类加载过程
加载》》验证》》准备》》解析》》初始化
加载:在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的 main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的 java.lang.Class对象,作为方法区这个类的各种数据的访问入口
验证:校验字节码文件的正确性
准备:给类的静态变量分配内存,并赋予默认值
解析:将符号引用替换为直接引用 ,该阶段会把一些静态方法(符号引用,比如 main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用
初始化:对类的静态变量初始化为指定的值,执行静态代码块

类被加载到内存方法区中时,主要包括运行时常量池,类型信息,字段信息,方法信息,类加载器的引用,对应class实例的引用等信息。

jdk7之前方法区被称为永久代,放在jvm内存中,静态变量和字符串常量放在堆中吗,运行时常量池放在永久代中
jdk8之后,方法区又称为元空间,不适用虚拟机内存,而是并直接使用物理内存,字符串常量池和静态变量仍然在堆当中;运行时常量池、类型信息、常量、字段、方法被移动都了元空间中。元空间默认大小为21M,会根据程序运行情况,动态调整,也可以在项目启动时指定元空间大小

java -Xms2048M -Xmx2048M -XX:MetaSpaceSize=256M -XX:MaxMetaSpaceSize=256M -jar source.jar

三、类加载器
1.引导类加载器,负载加载支撑JVM运行的 位于JRE的lib目录下得核心类库,比如rt.java,charsets.jar等
2.扩展类加载器ExtClassLoadder,负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
3.应用程序类加载器AppClassLoader负责加载classPath路径下的类包,主要就是加载程序员写的那些类
4.自定义加载器:负责加载用自定义路径下的类包

四、双亲委派机制
类加载器加载类会层层递交给上层加载器加载,如果上层加载器能加载就会加载,如果所有上层加载器都没加载,才会由当前类加载器加载。
两个好处:
沙箱安全机制,保证jvm核心类库能正确加载
保证类的唯一性 ,避免重复加载类

五、全盘负责委托机制
指一个ClassLoader装载一个类时,除非显示的使用另一个ClassLoader,否则该类所依赖及引用的类也由这个ClassLoader载入

六、自定义类加载器
继承ClassLoader
重写findClass和loadClass(如果想要打破双亲委派)

package com.danny.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoaderTest extends ClassLoader {
    private String classPath;

    public MyClassLoaderTest(String classPath) {
        this.classPath = classPath;
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                if (name.startsWith("java")) {
                    c = super.loadClass(name,resolve);
                } else {
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] data = loadData(name);
            return defineClass(name, data, 0, data.length);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ClassNotFoundException(name);
        }
    }

    private byte[] loadData(String name) throws IOException {
        String fileName = name;
        fileName = fileName.replaceAll("\.", "/") + ".class";
        String file = classPath + fileName;
        System.out.println(file);

        byte[] data = null;
        try (FileInputStream fis = new FileInputStream(new File(file))
        ) {
            int available = fis.available();
            data = new byte[available];
            fis.read(data);
        }
        return data;
    }

    public static void main(String[] args) throws ClassNotFoundException {
        MyClassLoaderTest myClassLoader = new MyClassLoaderTest("d:/test/");

        Class<?> clzz = myClassLoader.loadClass("com.danny.common.Person");
        System.out.println(clzz.getClassLoader().getClass().getName());

    }
}

在这里插入图片描述

七、 为什么打破双亲委派机制
根据不同的场景,可能西药加载到某些不同版本的类。例如Tomcat作为web服务器,会部署很多web应用,如果不同应用需要依赖不同版本的jar包,根据双亲委派机制,只会加载一次类,导致不同web应用拿到的是同一个版本的jar包,因此需要打破双亲委派机制。

八、什么时候对象会进入到老年代

  1. gc分代年龄达到默认次数,一般是第15次gc回收仍存活的对象会进入老年代,不同gc回收器可能不一样。由于对象头mark word中用4bit表示分代年龄,因此最多也就15次
  2. 大对象直接进入老年代,可以通过-XX:PretenureSizeThreshold设置大小
  3. 动态年龄判断,发生minor gc时,会计算分代年龄1+年龄2+…+年龄n等对象的大小是否超过Survivor 取50%,如果超过则把年龄n及以上的对象放入老年代

九、什么是TLAB
TLAB,即栈上分配。jvm会为每个栈分配一小块内存。如果对象经逃逸分析确定不会被栈桢以外访问,则会为其在栈上分配内存(前提是这个栈上内存能放得下这个对象)。这样可以让对象随着栈桢出栈而销毁,以降低GC垃圾回收压力

最后

以上就是心灵美夕阳为你收集整理的jvm学习笔记的全部内容,希望文章能够帮你解决jvm学习笔记所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部