> 文章列表 > JVM学习

JVM学习

JVM学习

JVM学习

jvm的位置

在这里插入图片描述

jvm的体系结构

在这里插入图片描述
在这里插入图片描述

类加载器

作用

加载class文件
在这里插入图片描述

1.虚拟机自带的加载器

2.启动类(根)加载器

3.扩展类加载器

4.应用程序(系统类)加载器

双亲委派机制

1.通过委派的方式,可以避免类的重复加载,当父加载器已经加载过某一个类时,子加载器就不会再重新加载这个类。
2.通过双亲委派的方式,还保证了安全性。因为Bootstrap ClassLoader在加载的时候,只会加载JAVA_HOME中的jar包里面的类,如java.lang.Integer,那么这个类是不会被随意替换的,除非有人跑到你的机器上, 破坏你的JDK。那么,就可以避免有人自定义一个有破坏功能的java.lang.Integer被加载。这样可以有效的防止核心Java API被篡改。

沙箱安全机制

了解即可:权限安全策略

Native

凡是带了native关键字的方法,说明Java的作用范围达不到,会去调用底层c语言的库;

会进入本地方法栈;

调用本地方法接口:JNI;

JNI作用:扩展Java的使用,融合不同的编程语言为java所用;最初仅想融合C、C++;

Java诞生时,C、C++流行,想要立足,必须要有调用C和C++的程序;

它在内存区域中,专门开辟了一块标记区域:Native Method Stack,登记native方法;

在最终执行时,加载本地方法库中的方法通过JNI。

应用:Java程序驱动打印机,管理系统,Robot类,企业级应用中较为少见。

调用其它接口:Socket、web Service、http。

PC寄存器

程序计数器:Program Counter Register.

每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码,是一个非常小的内存空间,几乎可以忽略不计。

方法区

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

静态变量、常量、类信息(构造方法,接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,与方法区无关。

static、final、Class模板、常量池

数据结构。

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

程序 = 框架 + 业务逻辑:吃饭;

栈:先进后出、后进先出:桶概念;

队列:先进先出,后进后出:管道排队概念;(FIFO:First Input First Output);

喝多了吐就是栈,吃多了拉就是队列。

栈:栈内存,主管程序的运行,生命周期和线程同步;线程结束,栈内存就释放;对于栈来说,不存在垃圾回收问题;一旦线程结束,栈就结束。

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

栈运行原理:栈帧

栈满了:StackOverflowError

栈+堆+方法区:交互关系;
在这里插入图片描述

三种JVM

  • Sun公司 HotSpot
  • BEA JRockit
  • IBM J9 VM

Heap:一个JVM只有一个堆内存;堆内存的大小是可调节的;

堆内存细分三个区域:

  • 新生区:Young/New

  • 老年区:Old

  • 永久区:Perm
    在这里插入图片描述

    垃圾回收:轻量级(针对伊甸园区)与重量级(FullGC:新生区);主要是在新生区与养老区;假设内存满了会报OOM(OutOfMemoryError),堆内存不够。

    在JDK8以后,永久存储区改名为元空间

新生区、老年区

  • 类 诞生和成长的地方,甚至死亡;

  • 伊甸园,所有的对象都是在伊甸园区新生,

  • 幸存者区(0,1)

    经过研究,99%的对象都是临时对象。

永久区

常驻内存,用来存放JDK自身携带的Class对象,interface元数据,存储的是Java运行时的一些环境或类信息;

这个区域不存在垃圾回收;关闭虚拟机就会释放永久区内存。

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

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

堆内存调优

在这里插入图片描述
在这里插入图片描述

元空间逻辑上存在,物理上不存在

默认情况下:分配的总内存是电脑内存的四分之一,而初始化的内存:六十四分之一;

-Xms1024m -Xmx1024m -XX:+printGCDetails

Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError

// -Xms 设置初始化内存分配大小,默认为1/64

// -Xmx 设置最大分配内存,默认为1/4

// -XX:+PrintGCDetails 打印GC垃圾回收信息

// -XX:+HeapDumpOnOutOfMemoryError OOM DUMP文件

OOM:

1.尝试堆内存空间扩大;

2.分析内存(内存快照分析工具JProfiler)

​ 1.分析dump内存文件,快速定位内存泄漏;

​ 2.获得堆中的数据;

​ 3.获得大的对象;

​ 4. …

GC 垃圾回收

在这里插入图片描述

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

  • 新生代
  • 幸存区(from,to:谁空谁是to)
  • 老年代

GC两种类别:轻GC(普通的GC),重GC(全局GC);

当一个对象经历了15(默认)次GC后,都还没有死,就会进入养老区

-XX:MaxTenuringThreshold=5 设置进入老年代的时间

1.每次GC都会将Eden中活的对象移到幸存区中:一旦Eden区被GC后,就会是空的;

GC(常用算法)

  • 标记清除算法
    在这里插入图片描述

    1.扫描对象:对活着的对象进行标记;

    2.清除扫描:对没有标记的对象进行清除。

    优点:不需要额外的空间!

    缺点:两次扫描,严重浪费时间,会产生内存碎片。

  • 标记整理/压缩法
    在这里插入图片描述

    对标记清除法的再优化:压缩:防止内存碎片产生,再次扫描,向一端移动存活的对象;

    标记清除压缩:先标记清除几次,再压缩

  • 复制清除算法:为了保证to区永远都是干净的
    在这里插入图片描述
    在这里插入图片描述
    好处:没有内存的碎片

    坏处:浪费了内存空间:多了一半空间永远是空to;假设对象100%存活(极端情况),开销极大

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

  • 引用计数算法(用的较少)
    在这里插入图片描述

内存效率:复制算法>标记清除法>标记压缩法(时间复杂度)

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

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

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

年轻代:

  • 存活率低,复制算法

老年代:

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

JMM:Java Memory Model

1.什么是JMM?

Java Memory Model。

2.它是做什么的?官方、其他人的博客、对应的视频

作用:缓存一致性协议,用于定义数据读写的规则(遵守,找到这个规则)。

JMM定义了线程工作内存与主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。
在这里插入图片描述

解决共享对象可见性这个问题:volatile

3.它该如何学习?

JMM:抽象的概念,理论
在这里插入图片描述

学习:volatile

总结

《深入理解Java虚拟机》