java虚拟机


layout: post title: "jvm虚拟机" subtitle: " "java虚拟机"" date: 2018-11-10 07:00:00 author: "青乡" header-img: "img/post-bg-2015.jpg" catalog: true tags: - jvm - 虚拟机

内存划分

线程栈
对象堆

内存回收

垃圾回收器

共7种
按新旧分
1.新对象
2.旧对象

按是否单线程分
1.单线程
2.多线程

最短停顿时间
就是回收最该回收的对象,回收尽量少的对象,一次回收数据少,所以使得jvm停顿时间最短。

回收算法

1.标记-删除
什么意思?
标记要删除的对象,然后删除。

其他的都是基于这个算法思想来的,只是改进它。因为缺点是,效率低。

2.标记-复制
分2个区,需要删除的复制到一个区,统一删除。

缺点,空间浪费。

3.标记-整理
复制算法太浪费空间,尤其是有的对象(老年代对象)存活比较久,不能删除。现在还是2个区,但是有一个区,要删除的对象统一放到一端,只对这一端进行删除。

4.标记-分代
1)新生代Eden
2)幸存1
3)幸存2

jvm都是采用的分代回收算法。

类如何加载

如何加载

由类加载器加载。加载到哪里去?jvm的内存。

类加载器

按父子分
1.父类加载器
2.子类加载类

按是否是jvm提供的类加载器分
1.jvm提供的类加载器
启动类加载器。
2.其他类加载器

按从开发者的角度分
1.启动类 //lib类加载器
jdk/lib
2.扩展类 //ext类加载器
jdk/lib/ext
3.类构建路径 //项目的类构建路径类加载器

4.开发者自定义类加载器


设计模式-双亲委派模型
见下文。


如何实现自定义类加载器?

类 extends ClassLoader{
    loadClass();
}
复制代码
设计模式-双亲委派模式

父加载器类这种设计模式到底是要解决什么问题?为什么要使用这个设计模式?
基础类,特别是lib目录下的rt.jar,尤其是Object,使用了父加载器类这种设计模式之后,就可以确保Object这个类始终是由lib加载器类加载,而不是其他的加载器类加载,这样jvm在运行时就只有一个唯一的Object字节码文件,不会导致错乱。


关键字
双亲
是父的意思,不是真的双的意思。就是父加载器类的意思。

委派
就是子委派/委托给父加载器类去加载一个类,哪怕有子加载器类。

所以,更好的名字应该是父加载器模式。


处理流程 按以下顺序委托加载器类,
1.父加载器类
2.lib加载器类
3.开发者自定义加载器类


源码

/**
     * Loads the class with the specified <a href="#name">binary name</a>.
     * This method searches for classes in the same manner as the {@link
     * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
     * machine to resolve class references.  Invoking this method is equivalent
     * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
     * false)</tt>}.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class was not found
     */
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    /**
     * Loads the class with the specified <a href="#name">binary name</a>.  The
     * default implementation of this method searches for classes in the
     * following order:
     *
     * <ol>
     *
     *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
     *   has already been loaded.  </p></li>
     *
     *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
     *   on the parent class loader.  If the parent is <tt>null</tt> the class
     *   loader built-in to the virtual machine is used, instead.  </p></li>
     *
     *   <li><p> Invoke the {@link #findClass(String)} method to find the
     *   class.  </p></li>
     *
     * </ol>
     *
     * <p> If the class was found using the above steps, and the
     * <tt>resolve</tt> flag is true, this method will then invoke the {@link
     * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
     *
     * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
     * #findClass(String)}, rather than this method.  </p>
     *
     * <p> Unless overridden, this method synchronizes on the result of
     * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
     * during the entire class loading process.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @param  resolve
     *         If <tt>true</tt> then resolve the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class could not be found
     */
    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); //首先,检查这个类是否已经被加载过:1.没加载,才需要加载 2.加载了,就不要再次加载了
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) { //排第一的是,父加载器类
                        c = parent.loadClass(name, false);
                    } else { //排第二的是,lib加载器类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) { //如果父加载器类和lib加载器类都没有找到这个类(在加载器类的各自查找目录里),才使用开发者自定义加载器类(排第三)
                    // 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自带的3个加载器类-源码
1.
2.
3.


jvm如何唯一的确定一个类?
1.类
2.加载器类
二者联合唯一确定一个类,即其中如果有一个不同,就不是同一个类,哪怕类全限定名一样。

唯一确定一个类具体是什么?

如何验证2个类是否一样?

类加载器与Class的关系

Every Class object contains a reference to the ClassLoader that defined it.
Class和ClassLoader有一层关系。


基本数据类型,没有加载器类,因为不需要。


Each instance of ClassLoader has an associated parent class loader.
每个加载器类与父加载器类有一层关系。什么关系?就是每个加载器类都必须有一个父加载器类,除了根加载器类(即lib加载器类),类似于所有的类都要继承根类Object。


Class
是什么?
jvm运行时,表示.class字节码文件。

作用?
各种类的信息,
1.类名字
2.字段
3.方法

类的生命周期

流程图


细节
共7步,
1.加载
加载.class文件到内存。

2.连接
1)验证
jdk版本。
2)准备
static 数据,赋值默认值。 //其他数据什么时候赋值默认值?

final 数据,赋值(非默认值)。 3)解析
符号引用——》直接引用。

3.初始化
初始化值。 1)static 数据,初始化值。 //其他数据什么时候初始化值?也是初始化的时候。 2)数据 = 赋值。

3)静态代码块

4.使用
new 对象完毕,访问对象的数据和方法。

5.回收 垃圾回收器回收。


验证
作用? 验证字节码是否规范,符合jvm的要求。不规范的后果是什么?1.程序错误;2.程序安全。

具体是验证什么东西?
格式验证 1.魔数 2.当前jvm版本与编译的字节码的jdb版本是否一致。

语义验证
1.各种关键字,比如final什么的
2.实现接口的所有方法
3.等等

程序控制流和数据流
1.主要是控制流,即程序执行的先后顺序。
2.类型转换
可以子到父,能不能父到子。


解析
符号引用——》直接引用
就是一些映射。
1.类全限定名——》类
2.字段名——》字段
3.方法名——》方法
4.等等


初始化
什么时候初始化?
有且只有5种情况。
1.new 对象
static 字段和方法
2.反射
3.父类
4.入口类/主类

5.还有一种
不常用。

对象的强引用和弱引用

1.强

类 o = new 类()。//o是强引用。只有当o = null时,对象才会被垃圾收集器回收。  
复制代码

2.弱

Project project = new Project();
Map m = new Map<Project,Integer>();
m.put(project,value); //假设现在project = null,但是对象还被map引用(map是弱引用),导致对象不能被回收。
复制代码

怎么实现?
jdk有WeakReference类,基于弱引用类的对象自动就是弱对象,弱对象会被自动回收,即不需要手动将弱引用置为null。

3.软
和弱差不多。

唯一的区别是,软引用是在内存不足的时候才回收;而弱引用,无论内存是否足够,都会被回收。

4.虚
很少使用。

作用 标识此对象已经被回收。


参考
www.jianshu.com/p/a7aaaf1bd…

java内存模型和jvm内存模型

happen-before

方法前面的代码,在后面的代码之前发生(即执行).

内存可见性

1.线程栈
线程都享,其他线程不可见。

2.对象堆
所有线程共享,都可见。

volatile

同步数据。

参考

www.jianshu.com/p/54eb60cfa…

www.importnew.com/23792.html

www.zhihu.com/question/27…

转载于:https://juejin.im/post/5bfc437ff265da614171417c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值