1.谈谈你对java的理解
1.平台无关性
2.面向对象
3.语言特性
4.异常处理
5.类库
5.GC
2.javap
javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。
javap -c 文件名(不带后缀的) 会打印在控制台上
一
1.为什么java能跨平台
图:为什么java能跨平台.png
二
1.JVM结构
1.类加载器(ClassLoader):在JVM启动时或者在类运行时将需要的class加载到JVM内存中。
2.执行引擎:执行引擎也叫做解释器(Interpreter),负责解释命令,提交操作系统执行
3.内存区(也叫运行时数据区)
4.本地方法接口:主要是提供非java,如C或C++实现的本地方法。
2.JVM如何加载class文件
类加载的过程:加载、验证、准备、解析、初始化、使用、卸载
1、加载
-------类加载器根据类全限定名获取二进制字节流,把二进制字节流加载到内存中,然后将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,在堆中生成相应的java.lang.Class的实例,作为对方法区中这些数据的访问入口。
-------加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中。
2、连接
-------2.1验证:确保被加载的类的正确性,包括文件格式验证,字节码验证,元数据验证,符号引用验证
验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用 -Xverifynone 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
-------2.2准备:为类的静态变量分配内存,并将其初始化为默认值
-------2.3解析:把类中的符号引用转化为直接引用
3、初始化
为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。
初始化的时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:
-------1)创建类的实例,也就是new的方式
-------2)访问某个类或接口的静态变量,或者对该静态变量赋值
-------3)调用类的静态方法
-------4)反射(如 Class.forName(“com.shengsiyuan.Test”))
-------5)初始化某个类的子类,则其父类也会被初始化
-------6)Java虚拟机启动时被标明为启动类的类( JavaTest),直接使用 java.exe命令来运行某个主类。
三
java反射机制
图:java反射机制.png
四
1.java类从编译到执行的过程(类的生命周期)
1.加载
2.连接
-------1.验证
-------2.准备
-------3.解析
3.初始化
4.使用
5.卸载
注:加载,验证,准备,初始化,和卸载这五个阶段顺序是固定的。而解析则不固定,某些情况下会在初始化之后才开始。
图:java类从编译到执行的过程.png
2.什么是ClassLoader
图:什么是ClassLoader.png
3.ClassLoader种类
图:ClassLoader种类.png
Java中的类加载器大体分为四类:
1.启动类加载器(Bootstrap ClassLoder): 负责加载JDK目录中\lib文件夹中的类,或者被-Xbootclasspath参数指定的路径下的可识别类。整个Java系统中很多基本组件都是有启动类加载器加载的,就连扩展类加载器和应用程序类加载器都是通过它加载的。在一个Java程序运行时,首先启动JVM,之后马上就诞生了启动类加载器,然后启动类加载器加载剩下两个系统加载器,之后这两个加载器再加载他们应该加载的类。
2.扩展类加载器(Extension ClassLoader):
负责加载JDK目录中\lib\ext文件夹中的类,或者被java.ext.dirs系统变量所指定的路径中的类库。这个类加载器的作用是用来与启动类加载器合作加载系统组件的。
3.应用程序类加载器(Application ClassLoader): 负责加载ClassPath路径下的类,可以通过getSystemClassLoader()获取。如果没有自己定义类加载,我们编写的Java类都将被这个类加载器加载。是程序中的默认类加载。
4.用户自定义类加载器(User ClassLoader): 用户自己编写的类加载器,可以通过覆盖findClass()方法去进行加载类。
4.类加载器的双亲委派机制
除了启动类加载器,每个类加载器都有一个父加载器。构成了一个类加载器结构系统。这个系统就是用来完成双亲委派机制的。
一个类加载器加载一个类时,首先会把加载动作委派给他的父加载器,如果父加载器无法完成这个加载动作时才由该类加载器进行加载。由于类加载器会向上传递加载请求,所以一个类加载时,首先尝试加载它的肯定是启动类加载器(逐级向上传递请求,直到启动类加载器,它没有父加载器),之后根据是否能加载的结果逐级让子类加载器尝试加载,直到加载成功。
图:类加载器的双亲委派机制.png
5.为什么要使用双亲委派机制去加载类
双亲委派是Java语言的一大创新。表明看起来,由于双亲委派机制的存在,类加载器的数量增多了不少,增加了程序的复杂性。不过存在既有道理。双亲委派机制让Java类体系变得稳定,有层次性能。特定的类由特定的类加载器加载,每次加载都委托父类的过程让 类对象在内存中的数量保持为一个,让同类名的类无法被替换。避免多份同样的字节码被加载
五
1.类的加载方式
图:类的加载方式.png
静态加载:
1、由 new 关键字创建一个类的实例
在由运行时刻用 new 方法载入
如:Dog dog = newDog();
动态加载:
2、调用 Class.forName() 方法
通过反射加载类型,并创建对象实例
如:Class clazz = Class.forName(“Dog”);
Object dog =clazz.newInstance();
3、调用某个 ClassLoader 实例的 loadClass() 方法
通过该 ClassLoader 实例的
loadClass() 方法载入。应用程序可以通过继承 ClassLoader 实现自己的类装载器。
如:Classclazz = classLoader.loadClass(“Dog”);
Object dog =clazz.newInstance();
2.类加载的三步过程(类的生命周期)
图:类加载的三步过程.png
1.加载
2.连接
-------1.验证
-------2.准备
-------3.解析
3.初始化
4.使用
5.卸载
注:加载,验证,准备,初始化,和卸载这五个阶段顺序是固定的。而解析则不固定,某些情况下会在初始化之后才开始。
图:java类从编译到执行的过程.png
3.loadClass和forName的区别
1.Class.forName得到的class是已经初始化完成的
2.Classloder.loaderClass得到的class是还没有链接(验证、准备、解析)的
六
0.JVM内存模型
JVM内存共分为虚拟机栈,本地方法栈,程序计数器(线程私有),堆,方法区(线程共享),五个部分
----------线程独享内存--------------
1.程序计数器
图:程序计数器.png
程序计数器是一块较小的内存空间,可以看做是当前线程锁执行的字节码行号指示器。字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令。因为一个处理器同一时间只会执行一条线程中的指令。因此为了线程切换后能恢复到正确的位置,每个线程都需要有一个独立的程序计数器。
2.虚拟机栈
图:java虚拟机栈.png
虚拟机栈描述的java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法执行时都会经历一个栈帧在虚拟机中入栈出栈这个过程。
-------局部变量表:(相当于我们经常说的栈),存放了编译期间可知的各种基本数据类型、对象引用(对象内存地址变量,指针或句柄)。空间在编译期间既分配完成。
-------操作数栈:在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)和
出栈(pop);某些字节码指令将值压入操作数栈,其余的字节码指令将操作数取出栈,使用它们后再把结果压入栈,比如:执行复制、交换、求和等操作;
图:局部变量表和操作数栈.png
3.本地方法栈:与虚拟机栈的作用一样,区别是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。 Native方法:java类库中用其他语言编写的方法,被Native关键字声明。
----------线程共享内存--------------
4.java堆(heap)
所有线程共享的内存区域,在虚拟机启动时创建。保存所有对象的实例和数组。
5.方法区
线程共享的内存区域,用于存储虚拟机加载的类信息、常量、静态变量、即时编译器、编译后的代码等。 堆的一个逻辑部分,HotSpot虚拟机在jdk8之前用永久代实现方法区,jdk8之后用元空间实现方法区。
在jdk7之后,原先在方法区的“字符串常量池”已被移动到了java堆中。元空间使用的是本地内存,不在受限于JVM本身内存。
七.
1.内存参数
1.-Xms Java Heap(堆)初始值,一但数据超过此之值,将会自动扩容,但最大只能扩展到-Xmx的值。;
2.-Xmx Java Heap(堆)可以扩展到的最大值,默认值为物理内存的1/4,最好将-Xms和-Xmx设为相同值,因为扩容会发生内存抖动,影响程序运行时的稳定性。
3.-Xss 每个线程的虚拟机栈的大小;
2.堆和栈的区别
1.栈存放的数据为编译期间可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)和对象引用。堆存放的所有对象的实例和数组
2.栈的内存随着线程执行结束自动释放。堆需要GC。
3.栈的空间占用比堆小
4.栈的执行效率比堆高。
3.JDK6和jdk6+版本的intern()方法的区别
JDK6:当调用intern()方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,将此字符串对象添加到字符串常量池中,并且返回该字符串的引用。
JDK6+:当调用intern()方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,如果该字符串对象已经存在于Java堆中,则将堆中此对象的引用添加到字符串常量池中,并且返回该引用;如果堆中不存在,则在池中创建该字符串并返回其引用。
七
1.java.lang.StackOverflowError异常
1.虚拟机栈或本地方法栈中的线程请求的栈帧的深度大于虚拟机所允许的深度。
2.java.lang.OutOfMemoryError异常
1.虚拟机栈或本地方法栈动态扩展时无法申请到足够的内存。
2.堆中没有内存来完成实例分配,并且堆也无法扩展时。
八
线程共享内存
1.MateSpace元空间比PermGen永久带的优势
图:MateSpace元空间比PermGen永久带的优势.png
十
1.jdk,jvm,jre的区别
1.JVM:Java Virtual Machine,运行java字节码的虚拟机
2.JRE:Java Runtime Environment 是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。
3.JDK:Java Development Kit JDK是Java开发工具包 JDK包含JRE,JRE包含JVM
2.HotSpot虚拟机的Client模式和Server模式的区别
1.编译器
-------1.client模式启动的时候,使用的是一个代号为C1的轻量级编译器
-------2.server模式启动的虚拟机采用相对重量级,代号为C2的编译器.
-------3.区别:C2比C1编译器编译的相对彻底,服务起来之后,性能更高
2.区别:
-------Client:更注重编译的速度,启动速度快,更适合用在客户端的版本下,针对GUI进行了优化
-------Server:更注重编译的质量,启动速度慢,但是运行效率高,适合用在服务器环境下,针对生产环境进行了优化
十一.
1.java8内存结构
图:java8内存结构图.png
2.虚拟机栈内存结构
图:虚拟机栈内存结构图.png