栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JVM快速入门

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JVM快速入门


目录
    • 1、JVM探究?
    • 2、JVM的位置?
    • 3、JVM的体系结构?
    • 4、类加载器
    • 5、双亲委派机制
    • 6、沙箱安全机制
    • 7、Native
    • 8、PC寄存器(Program Counter Register)
    • 9、方法区(Method Area)
    • 10、栈(Stack)
      • 栈、堆、方法区 关系
    • 11、三种JVM
    • 12、堆(Heap)
    • 13、新生区、老年区、永久区
    • 14、堆内存调优
    • 15、GC
      • 引用计数器
      • (1)复制算法
      • (2)标记清除算法
      • (3)压缩清除算法
    • 16、JMM

1、JVM探究?

几道面试题:

1、请你谈谈对jvm的理解?java8的虚拟机和之前的变化更新?
2、什么是oom?什么是栈溢出(StackOverflow) ?怎么分析?
3、jvm常见的调优参数有哪些?
4、内存快照如何抓取,怎么分析Dump文件?
5、谈谈jvm中,类加载器你的认识?

可以在cmd中输入java -version ,查看自己虚拟机的版本

2、JVM的位置?

3、JVM的体系结构?

JVM的调优是针对于方法区和堆 ;而大部分的调优针对于堆

JVM架构图

4、类加载器

作用:类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识。

package com.gd.Jvm;

public class Car {
    //类是模板,对象是具体的
    //进入JVM之后,先进入类加载器ClassLoader-> 然后初始化,得到Car类的Class对象
    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类对象是一致的
        Class aClass1 = car1.getClass();
        Class aClass2 = car2.getClass();
        Class aClass3 = car3.getClass();
        System.out.println(aClass1.hashCode());
        System.out.println(aClass2.hashCode());
        System.out.println(aClass3.hashCode());
    }

}


类加载器:

  • 虚拟机自带的加载器
  • 启动类加载器(根加载器)
  • 扩展类加载器
  • 应用程序加载器(系统类加载器)
        ClassLoader classLoader = aClass1.getClassLoader();
        System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(classLoader.getParent());//sun.misc.Launcher$ExtClassLoader@1540e19d   在jdk/jre/lib/ext 中
        System.out.println(classLoader.getParent().getParent());//null   (1)不存在 (2)java程序获取不到

应用程序加载器获取到的位于rt.jar 包下的java.lang 包下的ClassLoader 类

扩展加载器位于在jdk/jre/lib/ext 中

5、双亲委派机制

创建一个java.lang包,创建String类
重写toString方法,调用toString方法,出现异常
App -> Exc -> BooT(最终执行)
如果向上找,没找到对应的加载器,又会向下走,回到应用程序加载器

package java.lang;

public class String {
    
    @Override
    public String toString() {
        return "toString";
    }

    public static void main(String[] args) {
        String string =new String();
        String s = string.toString();
        System.out.println(s);
        System.out.println(s.getClass().getClassLoader());

    }

}


eg:再次创建一个包,创建一个类,类名定义为Student ,不与java定义的类重名

package com.gd.Jvm;

public class Student {
    @Override
    public String toString() {
        return "studentString";
    }

    public static void main(String[] args) {
        Student student =new Student();
        String s = student.toString();
        System.out.println(s); //studentString
        System.out.println(s.getClass().getClassLoader());//null
        new  Thread().start();
    }
    
}


线程类调用start方法,线程级别的java无法处理,就调用本地方法start()

6、沙箱安全机制

作用:防止恶意代码污染java源代码
守护了被信任的类库边界
将代码归入保护域,确定了代码可以进行哪些操作

比如我们定义了一个类名为String所在的包名为Java.lang,因为这个类本来属于jdk的,如果没有沙箱安全机制,这个类将会污染到系统中的String ,但是由于沙箱安全机制,所以就委托顶层的引导类加载器查找这个类,如果没有的话就委托给扩展类加载器,再没有就委托到系统类加载器。但是由于String就是jdk源代码,所以在引导类加载器那里就加载到了,先找到先使用,所以就使用引导类加载器里面的String ,后面的一概不能使用,这就保证了不被恶意代码污染。

package com.gd.Jvm;

public class Demo {
    public static void main(String[] args) {
        Demo demo =new Demo();
        demo.test1();
    }
    public void test1(){
        test2();
    }
    public  void test2(){
        test1();
    }
}

栈溢出

7、Native

1、会进入本地方法栈,调用本地方法接口 JNI
2、JNI作用:扩展Java的使用,融合不同的编程语言为java所用,最初为C 、 C++
Java诞生的时候,C 、C++ 横行,想要立足,必须要有调用 C 、C++的程序,它在内存区域中专门开辟了一块标记区域:Native Method Stack 用来登记native方法
3、在最终执行的时候,加载本地方法库中的方法通过JNI
4、Java程序驱动打印机,管理系统,目前该方法使用的越来越少了,在企业级应用已经比较少见。
5、现在的异构领域间通信很发达,调用其他接口:socket 、 http…

package com.gd.Jvm;

public class Demo1 {
    public static void main(String[] args) {
        new Thread(()->{

        },"hello").start();
    }

    private native void start0();
}

凡是带了native关键字的,说明java的作用范围达不到了, 回去调用底层c语言的库

8、PC寄存器(Program Counter Register)

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

9、方法区(Method Area)

方法区:static .final.Class .常量池… 运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关
方法区是所有线程共享的,所有字段和方法字节码,以及一些特殊方法
如:构造方法、接口代码;所有定义的方法的信息都保存在该区域,此区域属于共享空间。

public class Test {
    private  int a;
    private String name="jvmstudy";

    public static void main(String[] args) {
        Test test =new Test();
    }
}

10、栈(Stack)

1、栈是一种数据结构(后进先出),队列是先进先出的数据结构
2、为什么main方法是最先被执行的,但是最后结束?
main方法最先被压入栈,最后出栈

3、栈的别名:栈内存;主要管理程序的运行;生命周期与线程同步,线程结束,栈内存即被释放,
不存在垃圾回收的问题
4、栈里面存放的就是8大基本数据类型以及对象的引用以及实例方法
5、栈帧:是一片一片的…;压入一个方法入栈,就是栈帧
stack2:;先进来被调用
正在执行的方法,是位于栈顶的

栈、堆、方法区 关系

11、三种JVM

我们普遍使用的是sun公司提供的HotSpot

BEA
IBM的J9VM

12、堆(Heap)

一个JVM只有一个堆内存,堆内存的大小是可以调节的

Car car =new Car();
Class aClass =car.getClass();
//类加载器
ClassLoader classloader = aClass.getClassLoader(); 

类加载器读取了类文件后,将类,方法,常量 引用类的真实对象,存入堆中,堆划分为新生区,老年区,永久区
在新生区中进行垃圾回收,轻GC,经过伊甸园区随后进入到幸存0区,然后到幸存1区。
如果新生区满了,则进入老年区,重GC
如果老年区满了,则进入永久存储区
最终,内存满了,就会出现OOM,出现堆内存溢出的错误

  • eg:永久循环,造成了OOM的错误
13、新生区、老年区、永久区


注意:一般对象都是临时变量
永久代:存放class对象,变量等,不存在垃圾回收
在jdk1.8之后,永久存储区更改为元空间:逻辑存在,物理不存在
方法区里面为常量池
程序OOM了,该怎么办?:
(1)扩大堆内存,看结果
(2)分析内存,看那个地方出现了问题(专业工具)

1、在一个项目中,突然出现了OOM故障,那么该如何排除故障,研究为什么会出错?
(1)能够看到代码第几行出错,内存快照分析工具:MAT,JProfiler
(2)Debug,一行一行的分析
MAT,JProfiler的作用:
分析Dump内存文件,
快速定位内存泄漏
2、使用JProfiler工具分析OOM原因?
(1)在idea中安装插件
…以后更新

14、堆内存调优

eg:
默认: 分配的总内存是电脑内存的1/4 ; 初始化的内存 是电脑内存的1/64;

调整-Xms527m -Xmx527m -XX:+PrintGCDetails


调小看看
-Xms1m -Xmx1m -XX:+PrintGCDetails

15、GC

内存效率:复制算法>标记清除>标记压缩(时间复杂度)
内存整齐度:复制算法=标记压缩>标记清除
内存利用率:标记压缩=标记清除>复制算法
GC题目:
1、JVM的内存模型和分区模型,详细到每个区放什么?
2、堆里面的分区有哪些?Eden ,from,to ,老年区 ,说说各有什么特点?
3、GC的算法有哪些?
标记清除法、标记整理、复制算法、引用计数器
4、轻GC和重GC分别在什么时候发生?

引用计数器

首先给每个对象都分配一个引用计数器:计数器本身也会有消耗

(1)复制算法

from->to 谁空谁是to
每次GC:都会将Eden(伊甸园区) 活的对象移到幸存区,一旦Eden区被GC后,就会是空的!
好处:没有内存碎片
坏处:浪费了内存空间:多了一半空间永远是to,假设对象100%存活【极端情况】(比较危险)
最佳使用场景:对象存活度较低的时候:新生区用复制算法

(2)标记清除算法

(1)扫描这些对象,对活着的对象进行标记
(2)清除:对没有标记的对象,进行清除
优点:不需要额外的空间!
缺点:两次扫描,严重浪费时间,会产生内存碎片

(3)压缩清除算法

防止内存碎片产生,再次扫描,向一端移动存活的对象多了一个移动成本

  • 难道没有最优算法吗?
  • 没有,只有最合适的算法 - -> GC:分代收集算法
    年轻代:存活率低,复制算法
    老年代:区域大,存活率高;标记清除+标记压缩混合实现
16、JMM

1、什么是JMM?
Java Memory Model(Java内存模型), 围绕着在并发过程中如何处理可见性、原子性、有序性这三个特性而建立的模型。
2、干嘛的?
作用:缓存一致性协议,用于定义数据读写的规则(遵守,找到这个规则)
JMM规定了所有的变量都存储在主内存(Main Memory)中。每个线程还有自己的工作内存(Working Memory),线程的工作内存中保存了该线程使用到的变量的主内存的副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量(volatile变量仍然有工作内存的拷贝,但是由于它特殊的操作顺序性规定,所以看起来如同直接在主内存中读写访问一般)。不同的线程之间也无法直接访问对方工作内存中的变量,线程之间值的传递都需要通过主内存来完成
3、他该如何学习?
从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。本地内存它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化之后的一个数据存放位置

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/644988.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号