【Java面试高频问题】JVM基础知识

JVM

一、概述
  1. JVM和操作系统的关系:
    在这里插入图片描述
  2. JVM体系结构:
    在这里插入图片描述

程序计数器:选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

二、JVM类加载器&双亲委派机制
  1. 作用:加载class文件
public class Student {

    public static void main(String[] args) {

        // 实例化
        Student student1 = new Student();
        Student student2 = new Student();
        Student student3 = new Student();
        // 三个不同的对象
        System.out.println(student1.hashCode());
        System.out.println(student2.hashCode());
        System.out.println(student3.hashCode());
        // 获取类加载器
        Class<? extends Student> aClass = student1.getClass();
        System.out.println(aClass.getClassLoader()); // AppClassLoader(应用类加载器)
        // 获取父类加载器
        System.out.println(aClass.getClassLoader().getParent()); // ExtClassLoader(扩展类加载器):位置jre/lib/ext
        // 获取父类的父类加载器
        System.out.println(aClass.getClassLoader().getParent().getParent()); // null:java获取不到

    }
}

在这里插入图片描述
2. 双亲委派机制
在这里插入图片描述
当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
1)BootStrapClassLoader:启动类加载器,该ClassLoader是jvm在启动时创建的,用于加载 JAVA_HOME/jre/lib下面的类库;
2)ExtClassLoader:扩展类加载器,JAVA_HOME/jre/lib/ext下的类库;
3)AppClassLoader:应用程序类加载器,会加载java环境变量CLASSPATH所指定的路径下的类库;
4)CustomClassLoader:自定义类加载器,该ClassLoader是指我们自定义的ClassLoader。

比如定义一个Student类:

public class Student{

	@Override
	public String toString(){
		return "Hello!"
	}
	
	public static void main(String[] args) {
		Student s = new Student();
		System.out.println(s.toString());                 // Hello!
		System.out.println(s.getClass().getClassLoader());// sun.misc.Launcher$AppClassLoader@
    }
}
// 先去启动类加载器找,发现没有;再去扩展加载器还是没有;最终在应用加载器获取到了toString,成功加载 

双亲委派机制怎么保证安全的?
我们自己定义一个lang包:java.lang

package java.lang

public class String{

	 public String toString(){
	 	return "Helllo";
	 }
	 public static void main(String[] args) {
		String s = new String();
		System.out.println(s.toString());
    }
}
// 结果:错误: 在类 java.lang.String 中找不到main方法

原因:由于双亲委派机制,会去 rt.jar 找 java.lang.String,当然直接找到了,所以自己定义的该 String 类永远不会被调用!

  1. 总结:
  • 类加载器收到类加载的请求;
  • 一直向父类加载器委派,直到启动类加载器;
  • 如果父级加载器可以加载,就使用当前加载器,加载结束;若不能加载抛出异常,会交由子级加载器完成;
  • 重复上一步
三、沙箱安全机制

访问本地代码:
在这里插入图片描述
当远程代码需要使用操作系统和本地资源时,在jdk1.1,加入安全策略保证访问远程代码的安全性;jdk1.2加入代码签名保证安全;jdk1.6引入域的概念。

  • 沙箱组件:
  1. 字节码校验器:确保类文件遵循java编写规范;
  2. 类装载器:双亲委派机制保证恶意代码干涉;
四、native关键字&方法区内存
  1. Java平台有个用户和本地C代码进行互操作的API,称为Java Native Interface (Java本地接口即JNI)。
    使用 native 关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用;这些函数的实现体在DLL中,JDK的源代码中并不包含。
  2. 例如:创建一个Teacher teacher = new Teacher();
    (1):Class Teacher类通过类加载器,成为Teacher.class文件进内存;
    (2):在栈内存为Teacher开辟空间,并分配地址;
    (3):在堆内存为teacher对象开辟空间;
    (4):在堆内存对teacher对象的成员变量进行默认初始化;
    (5):对老师对象的成员变量进行显示初始化;
    (6):通过构造方法对老师对象的成员变量赋值;
    (7):老师对象初始化完毕,把对象地址赋值给teacher变量
五、栈
  • “喝多了吐就是栈,吃多了拉就是队列”

  • 为什么main()先执行,最后结束?
    栈:栈内存,主管程序的运行,生命周期和线程同步;
    线程结束,栈内存也就是释放,对于栈来说,不存在垃圾回收问题;
    一旦线程结束,栈就Over!

  • 栈运行原理:栈帧

  • 栈满了:StackOverflowError

六、堆
  1. 一个jvm只有一个堆,堆的大小可以手动调节;
    堆存储的类型:类、方法、常量、变量、所有引用类型的真实对象;
  2. 堆的分类:
    在这里插入图片描述
  3. 伊甸区:所有对象的出生的地方,也有可能是对象“死亡”的地方;
  4. 永久区:常驻内存,用来存放 jdk 自己携带的class,或类信息,当VM关闭时,会释放此处的内存;不存在垃圾回收;当一个启动类加载了太多的第三方jar包,或Tomcat部署了太多应用,或大量动态生成的反射类,或导致OOM;
    在这里插入图片描述
    元空间也称为非堆:因为它逻辑上存在,物理上不存在;新生区(YoungGen) + 老年代(OldGen) = 堆内存
  5. 堆内存溢出:java.lang.OutOfMemoryError:java heap space(OOM)
  6. VM堆内存
    在这里插入图片描述
  7. 修改堆内存大小:将初始内存和最大内存都改为 1024MB,并打印信息
    VM options : -Xms1024m -Xmx1024m -XX:+PrintGCDetails
  8. 分析oom原因:使用JProfiler工具
    JProfiler:
    是一款检查和跟踪系统Java程序性能的工具,JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。

IDEA下载插件:
在这里插入图片描述
客户端:https://www.ej-technologies.com/download/jprofiler/files
在这里插入图片描述
IDEA配置:
在这里插入图片描述
设置一个较小的堆内存:
VM options : -Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError
参数:-Xms 设置初始化内存分配大小(默认为:1/64);-Xmx 设置最大分配内存(默认为1/4)
当程序出现OutOfMemoryError:就会在JProfiler安装目录下 生成一个文件:.hprof文件,双击打开即可,可以查看到所占内存较大的对象、cpu使用率、线程等相关信息;
排查过程:1. 查看较大内存的对象;2. 查看线程信息,精准定位到oom之处

七、GC(垃圾回收机制<堆内发生>)
  1. 分类:轻GC、重GC
  2. 引用计数法:将对象的使用次数进行统计,然后会将引用次数少的进行回收
    在这里插入图片描述
  3. 复制算法:幸存区分为(from、to),从伊甸园活下来的对象会进入幸存区,两个幸村区是动态的,会交换对象,即从from–>to;
    在这里插入图片描述
  • GC一次的新生区变化:(深绿色表示有对象在内存中)
    将伊甸区GC到幸存to(因为to空),from的也会转移到to
    在这里插入图片描述
    此时from变to,to变from:
    在这里插入图片描述
    15次GC都没死亡的对象,进入养老区:
    在这里插入图片描述
  1. 标记清除算法(老年代主要的算法):
    在这里插入图片描述
    缺点:两次扫描浪费时间,存在内存碎片,
    优点:不用额外的空间
  2. 标记压缩算法:(老年代主要的算法,对标记清除算法的优化)
    在这里插入图片描述
    在这里插入图片描述
    总结:
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值