初识JVM

JVM

JVM的位置

在这里插入图片描述

JVM的体系结构

在这里插入图片描述

类加载器

作用:加载Class文件类,加载机制是将⼀个类从字节码⽂件转化为虚拟机可以直接使⽤类的过程

在这里插入图片描述

public class Car {

    public int age;

    public static void main(String[] args) {
        //类是模板,对象则是具体的

        Car car1 = new Car();
        Car car2 = new Car();
        Car car3 = new Car();

        System.out.println(car1.hashCode());
        System.out.println(car2.hashCode());
        System.out.println(car3.hashCode());

        Class<? extends Car> aClass1 = car1.getClass();

        ClassLoader classLoader = aClass1.getClassLoader();
        System.out.println(classLoader);//AppClassLoader

        System.out.println(classLoader.getParent());//ExtClassLoader
        System.out.println(classLoader.getParent().getParent());//null 1.不存在  2.获取不到(权限不够)
    }
}

在这里插入图片描述

  • 虚拟机自带的加载器
  • 启动类加载器
  • 扩展类加载器
  • 应用程序加载器

双亲委派机制

双亲委派模型的⼯作机制是:当类加载器接收到类加载的请求时,它不会⾃⼰去尝试加载这个类,⽽是

把这个请求委派给⽗加载器去完成,只有当⽗类加载器反馈⾃⼰⽆法完成这个加载请求时,⼦加载器才

会尝试⾃⼰去加载类。

类加载器收到类加载请求,将这个请求向上委托父类加载器去完成,一直向上委托,直到启动类加载器,启动加载器检查是否能够加载这个类。App–>EXC----->BOOT(最终执行)

好处

  1. 基于双亲委派模型规定的这种带有优先级的层次性关系,虚拟机运⾏程序时就能够避免类的重复加载。
  2. 双亲委派模型能够避免核⼼类篡改。⼀般我们描述的核⼼类是 rt.jar、tools.jar 这些由启动类加载器加载的类,这些类库在⽇常开发中被⼴泛运⽤,如果被篡改,后果将不堪设想。

##沙箱安全机制

沙箱是一个限制程序运行的环境,将代码限定在JVM特定运行范围中,并严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的 有效隔离,防止对本地系统造成破坏

在这里插入图片描述

##Native

package com;

public class Demo {
    public static void main(String[] args) {


        new Thread(()->{

        },"my thread name").start();
    }
    //nation:凡是带了nation 关键字的,说明java的作用范围达不到了,调用底层C语言库
    //会进入本地方法栈
    //调用本地方法本地接口JNI
    //JNI:扩展java使用,融合不同的编程语言为java所用,例如C,C++
    //在内存区域内专门开辟了一块标记区域:native Method Stack,登记native
    private native void hello();
    //调用其他接口:Socket,WebServer。。http

}

##PC寄存器

程序技术器

​ 每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向像一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。

##方法区

Method Area方法区

​ 方法区也叫静态区,是被所有线程共享,所有字段和方法字节码以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义的方法信息都保存在该区域,此区域属于共享区间。

方法区包含的都是整个程序中永远唯一的元素, class 信息 和 static修饰的变量

静态变量,常量,类信息,运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法去无关

static final Class 常量池:方法区

##栈

栈是一种数据结构

程序=数据结构+算法:持续学习

程序=框架+业务逻辑 简易工作理解

栈:先进后出

队列:先进先出,(FIFO:First Input First Output)都能操作

在这里插入图片描述

在这里插入图片描述

main方法先执行

  • 第一步把main方法压入栈中
  • 再压入其他方法
  • 弹出main方法结束

简易理解:栈也可以叫栈内存,主管程序的运行,生命周期和线程同步;线程结束,栈内存也就被释放,对于栈来说,不存在垃圾回收问题 一旦线程结束,栈也就over

栈:八大基本类型+对象引用+实例的方法

栈帧的理解:

在这里插入图片描述

栈+堆+方法区:交互关系

在这里插入图片描述

画出一个对象在内存中实例化的过程

##三种JVM

  • Sun公司 HotSpotJava HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)
  • BEAJRockit
  • IBMJ9 vm

我们学的都是HotSpot

##堆

Heap,一个jvm只有一个堆内存堆内存大小可以调节

类加载器读取了类文件后,一般会把类,方法,常量放到堆中,保存我们所有引用类型的对象。

堆内存中还要细分为三个区域

  • 新生区(伊甸园区eden)Yong/New
  • 老年区 old
  • 永久区

在这里插入图片描述

GC垃圾回收,主要是在伊甸区和养老区

假设内存满了,OOM,堆内存不够 java.lang.OutOfMemoryError:java heap space

##新生区,老年区

  • 类:诞生和成长的地方,甚至是死亡
  • 伊甸区,所有的对象都是在伊甸区new出来的
  • 存活区

经过研究,99%的对象都是临时对象,活不到老年区。

新生代又分为伊甸区(Eden) 存活区(Survivor),其中存活区又分为两个大小空间一样的s0、s1,而且s0 和 s1 可以互相转化,存活区保存的一定是在伊甸区保存了很久的,并且经过好几次小的GC还存活下来的对象,存活区一定会有两块大小相等的空间。目的是一块存活区未来的晋升,另一块存活区是为了对象的回收。需要注意的是:这两块存活区一定有一块是空的

##永生区

这个区域常驻内存,用来存放JDK自身携带的Class对象,Interface元数据,存储的是java运行时的一些环境或者类信息,这个区域不存在垃圾回收!关闭VM虚拟机的时候会释放这个区域的内存

一个启动类,加载了大量的第三方jar包。Tomcat部署了太多的应用,大量动态生成的反射类,不断的被加载。直到内存满,就会出现OOM(OutOfMemoryError);

  • jdk1.6:永久代,常量池是在方法区中;
  • jdk1.7:永久代,但是慢慢的退化了,常量池在堆中
  • jdk1.8:无永久代,常量池在元空间

在这里插入图片描述

在这里插入图片描述

逻辑上存在,实际不存在

##堆内存调优

堆内存调优代码:

设置VM大小 //-Xms1024m -Xmx1024m -XX:+PrintGCDetails

package com;

public class Demo02 {
    public static void main(String[] args) {
        //返回虚拟机试图使用的最大内存
        long max = Runtime.getRuntime().maxMemory();        //字节  1024*1024
        //返回jvm的初始化总内存
        long total = Runtime.getRuntime().totalMemory();

        System.out.println("max ="+max+"字节\t"+(max/(double)1024/1024)+"MB");
        System.out.println("total ="+max+"字节\t"+(total/(double)1024/1024)+"MB");
    }
    //OOM
    //1.尝试扩大堆内存查看结果
    //2.分析内存,看一下那个地方出错了
    //-Xms1024m -Xmx1024m -XX:+PrintGCDetails
}

在这里插入图片描述

在一个项目中,突然出现了OOM故障,那么该如何排除,研究为什么出错

  • 能够看到代码第几行出错:内存快照分析工具,MAT,Jprofile
  • Dubug,一行行区分析

MAT,Jprofile作用

  • 分析Dump内存文件,快速定位内存泄露
  • 获得堆中的数据
  • 获得大的对象

通过Jprofile工具解决问题:狂神JVM视频p9

##GC

JVM在进行GC时,并不是堆这三个区域统一回收,大部分回收的都是新生代

  • 新生代
  • 幸存区(from和to两个区域)
  • 老年区

GC两种分类:轻GC(普通的GC)和重GC(全局GC)

GC的算法:标记清除法,标记压缩法,复制算法,引用计数器

复制算法

在这里插入图片描述

在这里插入图片描述

  • 好处:没有内存的碎片
  • 坏处:浪费了内存空间:多了一般空间永远时空的(to)

复制对象最佳使用的场景:对象存活度低的时候(及新生区)

标记清除法

在这里插入图片描述

  • 优点:不需要额外空间
  • 缺点:两次扫描,严重浪费时间,会产生内存碎片

标记压缩

在这里插入图片描述

GC总结:

内存效率:复制算法>标记清除算法>标记压缩算法

内存整齐度:复制算法=标记清除算法>标记压缩算法

内存利用率:标记压缩算法>标记清除算法>复制算法

没有最好的算法,只有最合适的算法。GC:分代收集算法

年轻代:

  • 存活率低
  • 复制算法

老年代:

  • 区域大,存活率高
  • 标记清除+标记压缩混合实现

多找时间学习JVM

  • 优点:不需要额外空间
  • 缺点:两次扫描,严重浪费时间,会产生内存碎片

标记压缩

[外链图片转存中…(img-M9KKuZur-1602681619630)]

GC总结:

内存效率:复制算法>标记清除算法>标记压缩算法

内存整齐度:复制算法=标记清除算法>标记压缩算法

内存利用率:标记压缩算法>标记清除算法>复制算法

没有最好的算法,只有最合适的算法。GC:分代收集算法

年轻代:

  • 存活率低
  • 复制算法

老年代:

  • 区域大,存活率高
  • 标记清除+标记压缩混合实现

多找时间学习JVM

推荐书《深入理解JVM》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值