Java复习笔记之JVM内存模型

谈谈你对java的理解

平台无关性

GC

语言特性

面向对象

类库

异常处理

 

Compile Once, Run Anywhere如何实现?

通过java虚拟机

java源码首先被编译成字节码,再由的不同平台的JVM进行解析,java语言在不同的 平台上运行时不需要进行重新编译,java虚拟机在执行自己码的时候,把字节码转换成具体平台上的机器指令

 

为什么JVM不直接将源码解析成机器码去执行

  准备工作:每次执行都需要各种检查

  兼容性:也可以将别的语言解析成字节码

 

 

JVM如何加载.class文件?

 

Class Loader: 依据特定格式,加载Class文件到内存中

Execution Engine: 对命令进行解析

Native Interface: 融合不同开发语言的原生库为java所用

Runtime Data Area: JVM内存空间结构模型

 

谈谈java的方射

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

 

一个简单的放射例子

 

类从编译到执行的过程

  编译器将Robot.java源文件编译为Robot.class字节码文件

  ClassLoader将字节码转换为JVM中的Class<Robot>对象

  JVM利用Class<Robot>对象实列化为Robot对象

 

谈谈ClassLoader

ClassLoader在java中有着非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流。它是java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流装载进系统,然后交给java虚拟机进行连接,初始化等操作。

 

ClassLoader的种类

BootStrapClassLoader: C++编写,加载核心库java.*

ExtClassLoader: java编写,加载扩展库javax.*

AppClassLoader: java编写,加载程序所在目录

自定义ClassLoader: java编写,定制化加载

 

自定义ClassLoader的实现

关键函数:

protected Class<?> findClass(String name) throws ClassNotFoundException{

  Throw new ClassNotFoundException(name)

}

protected  final Class<?> defineClass(byte[] b, int off, int len) throws ClassFormatError{

 return defineClass(null, b, off, len, null);

}

 

 

谈谈类加载器的双亲委派机制

 

当一个类要加载的时候,若不考虑自定义的类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理会先检查自己是否已经加载过,如果没有再往上。直到到达Bootstrap classLoader之前,都是没有哪个加载器自己选择加载的。如果父加载器无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。

 

为什么要使用双亲委派机制去加载类

   避免多份同样字节码加载

 

类的加载方式

  隐式加载:new

  显式加载:loadClass, forName等

 

 类的装载过程

  1. 加载:通过ClassLoader加载class文件字节码,生成Class对象
  2. 连接:
    1. 校验:检查加载的class的正确性和安全性
    2. 准备:为类变量分配存储空间并设置类变量初始值
    3. 解析:JVM将常量池内的符号引用转换为直接引用

    3.初始化:执行类变量赋值和静态代码块

 

 

 

LoadClass和forName的区别

 Class.forName得到的class是已经初始化完成的 (jdbc注册驱动)

 Classloader.loadClass得到的class是还没有连接的 (spring延迟加载)

 

 java内存模型:

  内存简介:

    

地址空间的划分:

   内核空间:独立于普通应用程序,运行在较高的特权级别上,它们驻留在被保护的内存空间上,拥有访问硬件设备的所有权限。

   用户空间:运行在用户空间的应用程序只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,也不能直接访问内核空间和硬件设备,以及其他一些具体的使用限制。

 

JVM内存模型——JDK8

  

线程独占部分:

程序计数器(Program Counter Register)

  当前线程所执行的字节码行号指示器(逻辑)

  改变计数器的值来选取下一条需要执行的字节码指令

  和线程是一对一的关系即“线程私有”

  对java方法计数,如果是native方法则计数器的值为undefined

  不会发生内存泄露

 

Java虚拟机栈(Stack)

   Java方法执行的内存模型

   包含多个栈帧(栈帧存储:局部变量表,操作数栈,动态连接,返回地址)

 

本地方法栈(native)

   与虚拟机栈相似,主要作用于标注了native的方法

 

局部变量表和操作数栈

   局部变量表:包含方法执行过程中的所有变量

   操作数栈:入栈,出栈,复制,交换,产生消费变量

 

递归为什么会引发java.lang.StackOverflowError异常

   递归过深,栈帧数超出虚拟栈深度的(每次递归都会创建一个栈帧,而且会保存当前栈帧的引用的,过多层数会撑爆虚拟机栈)

 

虚拟机栈过多会引发java.lang.OutOfMemoryError异常

 

 

 

线程共享部分:

元空间(MetaSpace)与永久代(PermGen)的区别

   都是方法区的实现

   元空间使用的是本地内存,而永久代使用的是jvm内存(java.lang.OutOfMemoryError:PermGen space)

 

MetaSpace相比PermGen的优势   

   字符串常量池存在永久代中,容易出现性能问题和内存溢出

   类和方法的信息大小难以确定,给永久代的大小指定带来困难

   永久代会为GC带来不必要的复杂性

   方便HotSpot与其他JVM如Jrockit的集成

 

Java堆(Heap)

  对象实例的分配区域

  GC管理的主要区域(新生代(Eden, survice0, survice1,老年代)

 

 

JVM内存模型常见面试题:

JVM三大性能调优参数 -Xms, -Xmx, -Xss的含义

  Java -Xms128m,  -Xmx128, -Xss256k  -jar xxxx.jar

-Xss: 规定了每个线程虚拟机栈(堆栈)的大小

-Xms: 堆的初始值

-Xmx: 堆能达到的最大值

 

Java内容模型中的堆和栈的区别——内存分配策略

  静态存储:编译时确定每个数据目标在运行时的存储空间需求

  栈式存储:数据区需求在编译时未知,运行时模块入口前确定

  堆式存储:编译时或运行时模块入口都无法确定,动态分配

联系:引用对象,数组时,栈里定义变量保存堆中目标的首地址

  1. 管理方式:栈自动释放,堆需要GC
  2. 空间大小:栈比堆小
  3. 碎片相关:栈产生的碎片远小于堆
  4. 分配方式:栈支持静态和动态分配,而堆仅支持动态分配
  5. 效率:栈的效率比堆高

 

不同JDK版本之间的intern()方法的区别——JDK6 VS JDK6+

  String s = new String(a)  ;  s.intern();

  JDK6:当调用intern方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,将此字符串对象添加到字符串常量池中,并且返回该字符串对象的引用。

  JDK6+: 当调用intern方法时,如果字符串常量池中先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,如果该字符串对象已经存在java堆中,则将堆中对此对象的引用添加到字符串常量池中,并且返回该引用;如果堆中不存在,则在池中创建该字符串并返回其引用。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值