JVM探究

目录

常见面试题

整体内容:

内容答案:

1.JVM位置

2.JVM体系结构

 3.内加载器

 4.双亲委派机制

 5.沙箱安全机制

6.Native关键字

7.PC寄存器

8.方法区

9.栈 

 10.三种JVM

11.堆 

 12.新生区,老年区

13.永久区:

14.堆内存调优:

15.GC常用算法

16.JMM

17.总结 


常见面试题

  • 请你谈谈对jvm的理解?java8虚拟机和之前的变化跟新?
  • 什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
  • JVM常见调优参数有哪些?
  • 内存快照如何抓取,怎么分析Dump文件?知道吗?
  • 谈谈JVM中类加载器你的认识?

整体内容:

  1. JVM位置  
  2. JVM体系结构
  3. 类加载器
  4. 双亲委派机制
  5. 沙箱安全机制
  6. Native
  7. PC寄存器
  8. 方法区
  9. 三种JVM
  10. 新生区,老年区
  11. 永久区 
  12. 堆内存调优 
  13. GC  常用算法
  14. JMM
  15. 总结

内容答案:

1.JVM位置

JVM是位于操作系统之上的一个运行java的虚拟机,可以于其他环境并列

2.JVM体系结构

jvm加载是先从电脑的磁盘中找到该java文件,加载成class文件然后在进行类加载器,去运行到运行数据区,jvm运行时数据区有:方法区,java栈,本地方法栈,堆,程序计数器,等等.....

 

而在,java栈,本地方法区,和程序计数器中一定不会有垃圾,一般的jvm调优都是在堆中进行垃圾回收调优的. 

 

 3.内加载器

作用:加载Class文件

  1. 虚拟机自带的加载器
  2. 启动类(根)加载器
  3. 扩展类加载器
  4. 应用程序加载器(类加载器)

根加载器>扩展类加载器> 应用程序加载器

 4.双亲委派机制

双亲委派机制有三层如:

  • Bootstrap classLoader:根加载器,主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和APPClassLoader。
  • ExtClassLoader:扩展类加载器,主要负责加载jre/lib/ext目录下的一些扩展的jar。
  • AppClassLoader:应用程序加载器主要负责加载应用程序的主函数类

当一个对象被加载的时候:

  1. 类加载器会受到加载的请求
  2. 这个请求向上委托父类加载器去完成,一直向上委托,直到启动类加载器
  3. 启动加载器检查是否能够加载当前这个类,能加载就结束使用当前的类加载器,否则抛出异常通知子加载器进行加载,

将会进行重复3次的步骤,此外根加载器是获取不到的因为根加载器使用c/c++写的:

package com.tang.Servlet.test;

public class Car {
    public static void main(String[] args) {
        ClassLoader classLoader = Car.class.getClassLoader();
        System.out.println(classLoader);//输出应用类加载器
        System.out.println(classLoader.getParent());//输出扩展类加载器(平台类加载器)
        System.out.println(classLoader.getParent().getParent());//获取不到跟加载器
    }
}

输出:

jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
jdk.internal.loader.ClassLoaders$PlatformClassLoader@4c203ea1
null

小历史:创建java的时候创作者是想要抛出c++的指针和内存管理这些繁琐的过程,进行创建java这门语言,所以现在这些繁琐的内存管理,JVM已经帮我们做好了,如此java也被戏称为C++--.

 5.沙箱安全机制

 作用:早期用来保证对代码的有效隔离,防止对本地系统造成破坏,调用他人编写的代码,具体可查看:

java中的安全模型(沙箱机制)_改变ing的博客-CSDN博客_沙箱安全机制

6.Native关键字

作者理解:Native基本用来于c/c++交互进行调用别的语言函数,或者接口,进入本地方法库查找,如开启线程就需要去调用底层的函数.

Native Method Stack

它具体的用法是Native method Stack中登记Native方法,在(Execution Engine)执行引擎执行的时候加载Native Libraies。[本地库]

7.PC寄存器

作者理解:pc寄存器就是运行数据区中的计数器,准确来说是用来记录线程的目标需要干什么.

线程计数器:Program Counter Register

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

8.方法区

Method Area 方法区

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

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

static final Class 常量池 

9.栈 

栈是一种数据结构

  • 栈:先进后出
  • 队列:后进先出 

例如:喝多了吐就是栈,吃多了拉就是队列.

栈:栈内存主管程序的运行,生命周期于线程同步.

线程结束栈内存也就释放,对于栈来说不存在,垃圾回收问题,一旦线程结束栈也跟着结束了.

栈中存放:8大基本数据类型+对象引用+实例的方法 

 

栈运行原理:栈帧

如果栈满了则会抛出StackOverflowError

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

 10.三种JVM

通过Dos命令java -version 查看当前jvm的版本信息如:

 

  • Sun公司 HotSpot  Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.12+8-LTS-237, mixed mode)
  • BEA公司 JRocket
  • IBM公司 j9 vm

我们都是通过HotSpot迅即进行学习的

11.堆 

堆(Heap),一个jvm只有一个堆内存,堆内存的大小是可以调节的.

类加载器读取了类文件之后,一般会把什么东西放在堆中?类,方法,常量,变量,保存我们所有引用类型真实对象;

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

  • 新生区(伊甸园区) Young/New
  • 养老区   old
  • 永久区   Perm

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

假设内存满了就会报OOM错误,堆内存不够!报: java.lang.OutOfMemoryError: Java heap space

在JDK8以后永久存储区改了个名字叫做元空间;

 12.新生区,老年区

新生区:

  • 类:诞生和成长的地方,甚至死亡  .
  • 伊甸园区,所有的对象都是在伊甸园区new出来的!
  • 幸存者区(0,1)

 

 真理:经过研究,99%的对象都是临时对象!

老年区: 

在新生区淘汰不掉的就进入了老年区(养老区); 

13.永久区:

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

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

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

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

public class test {
    public static void main(String[] args) {
        //返回虚拟机试图使用的最大内存
        long max = Runtime.getRuntime().maxMemory();    //字节为单位
        //返回虚拟机运行时的总内存
        long total = Runtime.getRuntime().totalMemory();
        System.out.println("max="+max+"字节\t"+(double)(max/1024/1024)+"MB");
        System.out.println("total="+total+"字节\t"+(double)(total/1024/1024)+"MB");

        //默认情况下堆内存分配总内存是:电脑的1/4,而初始化的内存是1/64
        //-Xms1024m -Xms1024m -XX:+PrintGCDetails
        //遇到OOM解决方案:
        //1.尝试扩大内存空间查看结果
        //2.分析内存查看那个地方出现了问题(专业工具)
    }
}

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

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

MAT,Jprofiler作用:

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

14.堆内存调优:

可以进行堆内存的大小初始化调整. 

package Tang;

import java.util.ArrayList;

//-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
public class test3 {
    byte[] a= new byte[1*1024*1024];//表示1m(1兆)

    public static void main(String[] args) {
        //-Xms 初始化内存大小,默认电脑内存的1/64
        //-Xmx 最大分配内存,默认电脑内存的1/4
        //-XX:+PrintGCDetails 打印GC信息
        //-XX:+HeapDumpOnOutOfMemoryError  如果是内存不足错误就打印出堆的Dump文件

        ArrayList<Object> test3 = new ArrayList<>();
        int temp=0;
        try {
            while (true){
                test3.add(new test3());//问题所在
                temp++;
            }
        } catch (OutOfMemoryError e) {
            System.out.println("增加次数"+temp);
            e.printStackTrace();
        }
    }
}

15.GC常用算法

GC:是垃圾回收的守护线程,可通过System.gc()手动实现调用.

GC作用域是在方法区和堆里,因为只有这两个地方才会产生垃圾对象

 

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

  • 新生代
  • 幸存区(from to)
  • 老年区

GC两种类型:轻GC(普通GC),重GC(全局GC)

 GC题目:

  • JVM内存和分区~详细到每个区放什么~
  • 堆里面的分区有哪些~Eden,from,to,老年区,说说他们的特点~
  • GC的算法有哪些?标记清除法,标记压缩,复制算法,引用计数器怎么用的?
  • 轻GC和重GC分别在什么时候发生?

 引用计数法:

 

 复制算法:

  •  好处:没有内存碎片
  •  坏处:浪费了一个幸存区的空间,to区永远是空的.. 

 复制算法最佳使用场景:对象存活较低的时候

标记压缩清除算法: 

标记清除:

  • 优点: 弥补了复制算法的不足,未浪费空间.
  • 缺点:两次扫描,严重的浪费了时间,会产生内存碎片。

 标记压缩清除算法优化:

 

  • 优点: 不在产生实现碎片,使空间连续,弥补了复制算法的不足.
  • 缺点:三次扫描,严重的浪费了时间。

16.JMM

1.什么是JMM?

        Java Memory Model(java内存模型)简称JMM

2.他是干嘛的?

        作用:缓存一致性协议,用于定义数据读写规则!

17.总结 

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

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

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

思考:难道没有最好的算法吗?

答案:没有,没有最好的算法,只有合适的算法.-->GC是分代收集算法

年轻代: 

  • 对象存活率低
  • 使用复制算法

老年代:

  • 对象存活率高
  • 使用标记清除(内存碎片不是太多的情况下)+标记压缩清除算法.

文章大部分参考于:【狂神说Java】JVM快速入门篇_哔哩哔哩_bilibili 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

123小步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值