jvm源码浅谈

浅谈jvm

java虚拟机加载源码分析

  /**
   * 首先c++创建java虚拟机和引导类加载(BootStrapApplication),然后引导类加载器加载Launcher,通过Launcher创建其他类加载器。
   */
  1.getLauncher()单例的Lanuncher
   public static Launcher getLauncher() {
        return launcher;
    }
  2.初始化Lanucher中的扩展类加载器(ExtClassLoader)和应用类加载器(AppClassLoader)
    public Launcher() {
    var1 = Launcher.ExtClassLoader.getExtClassLoader();
    this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
    }
  3.getAppClassLoader(var1)方法默认从classpath加载资源,var1是扩展类加载器,扩展类加载器此处指定是确定应用类加载器默认生成的时候继承了ClassLoader类的parent属性,parent=ExtClassLoader,同理ExtClassLoader.parent=BootStrapClassLoader=null
   public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
            final String var1 = System.getProperty("java.class.path");
            final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
            return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
                public Launcher.AppClassLoader run() {
                    URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
                    return new Launcher.AppClassLoader(var1x, var0);
                }
            });
        }

        AppClassLoader(URL[] var1, ClassLoader var2) {
            super(var1, var2, Launcher.factory);
            this.ucp.initLookupCache(this);
        }

双亲委派机制源码解析

//Layncher类加载loadClass(name,?) 安全校验代码省略,看核心代码
   public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
                return super.loadClass(var1, var2);
            }
        }
//ClassLoader
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) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                    	//父类加载器不为null 直接交有弗雷加载器重新执行LoadClass
                        c = parent.loadClass(name, false);
                    } else {
                    	//ext期待类加载器无法加载,直接交由引导类加载器加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    //加载器开始加载类,抛出异常ClassNotFoundException
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

双亲委派首先判断类是否被加载,应用类加载器没有被加载才会交给parent(ext),ext未加载交给parent(bootStrap)

面试

package java.lang;
public class String {
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}
//运行结果
错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
   public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application

答:1.双亲委派机制是父类先行加载,父类无法加载,子类才可加载。
     2.引导类加载器加载rt.jar核心包时,发现里面有java.lang.String包,已经加载完毕,然后运行String下的main方法,发现没有main方法可以运行,故报错。

1.自定义类加载器加载Class类 MyClassLoader 自定义类加载器继承ClassLoader类,实现findClass方法,重写具体的业务逻辑,代码如下:

public class MyClassLoader extends ClassLoader {
	//获取类的加载路径
    private String classPath;
    public MyClassLoader(String classPath) {
        this.classPath = classPath;
    }
	//把需要加载的class文件Io流读取
    private byte[] loadByte(String name) throws Exception {
      	//加载路径替换
        name = name.replaceAll("\\.", "/");
        //加载类的Class文件,转化为字节数据
        FileInputStream fis = new FileInputStream(classPath + "/" + name
                + ".class");
        int len = fis.available();
        byte[] data = new byte[len];
        fis.read(data);
        fis.close();
        return data;
    }
    //类加载器在在使用自定义的findClass加载器加载文件
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] data = loadByte(name);
            //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节
            return defineClass(name, data, 0, data.length);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        }
    }
}

如何打破双亲委派机制? tomcat容器加载多个war就是采用了此思想。

//首选需要重写ClassLoader类的findClass方法,之后写业务逻辑
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) {
                long t0 = System.nanoTime();
                try {
                //打破双亲委派机制,如果加载的name是以此name开头的,采用自定义的findClass直接加载到jvm虚拟机,否则继续执行双亲委派机制。
                    if (name.startsWith("com.hello.jvm")) {
                        c = findClass(name);
                    } else {
                        c = this.getParent().loadClass(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

双亲委派机制: 主要是为了防止外部人员修改JDK源码级别的东西,防止入侵,还有就是避免了类的重复加载。完结!!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值