【Java】简历对应技术整理-包含JVM

Java基础

1. 编译型语言VS解释型语言

编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。因此效率比较高。比如 C 语言。

解释型语言:程序不需要编译,程序在运行时才翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。比如Basic语言,专门有一个解释器能够直接执行Basic程序,每个语句都是执行的时候才翻译。

 

C语言是编译型的。C程序——>机器语言(编译)

Java比较特殊,Java程序也需要编译,但是没有直接编译成机器语言,而是编译成字节码,然后用解释方式执行字节码。 Java程序—— >字节码(编译)—— >机器语言(解释)

2. JVM工作原理

JVM 主要由  ClassLoader   行引擎 两子系统 组成,运行数据区分为五个部分: 方法区、堆、栈、程序计数器、本地方法栈其中的方法区和堆是所有线程共享的,JVM将临时变量放在栈中,每个线程都有自己独立的栈空间和程序计数器

任何一个Java类的main函数运行都会创建一个JVM实例,当main函数结束时,JVM实例也就结束了。JVM实例启动时默认启动几个守护线程,比如:垃圾回收的线程,而 main 方法的执行是在一个单独的非守护线程中执行的。只要母线程结束,子线程就自动销毁,只要非守护main 线程结束JVM实例就销毁了。

那么在Java类main函数运行过程中,JVM的工作原理如下:

(1) 根据系统环境变量,创建装载JVM的环境与配置

(2) 寻找JRE目录,寻找jvm.dll,并装载jvm.dll;

(3) 根据JVM的参数配置,如:内存参数,初始化jvm实例;

(4) JVM实例产生一个引导类加载器实例(Bootstrap Loader),加载Java核心库,然后引导类加载器自动加载扩展类加载器(Extended Loader),加载Java扩展库,最后扩展类加载器自动加载系统类加载器(AppClass Loader),加载当前的Java类;

(5) 当前Java类加载至内存后,会经过验证、准备、解析三步,将Java类中的类型信息、属性信息、常量池存放在方法区内存中,方法指令直接保存到栈内存中,如:main函数;

(6) 执行引擎开始执行栈内存中指令,由于main函数是静态方法,所以不需要传入实例,在类加载完毕之后,直接执行main方法指令;

(7) main函数执行主线程结束,随之守护线程销毁,最后JVM实例被销毁;

3. JVM类加载机制

类加载是Java程序运行的第一步,在java.lang包里有个ClassLoader类,ClassLoader 的基本目标是对类的请求提供服务,按需动态装载类和资源,只有当一个类要使用(1.Class.forName();2.调用类的静态方法;3.使用 new 关键字来实例化一个类)的时候,类加载器才会加载这个类并初始化。当我们自定义类加载器加载类文件时(继承自ClassLoader类,只需覆盖 findClass方法,即可),其类加载机制如下:

当自定义类加载器加载类时,会调用loadClass方法加载类,而由于类加载的双亲委托模式,会将类的加载代理给父类加载器:系统类加载器来完成,依次类推至最顶层引导类加载器加载,如果父类加载器没有加载到类,则最终返回由自定义类加载器加载类,通过双亲委托模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类。

需要说明一下Java虚拟机是如何判定两个Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。然而,类加载器又分初始类加载器定义类加载器,由于类加载的代理模式,初始类加载器并不一定是定义类加载器,所以确切的说,判定两个 Java 类是否相同的, 哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。

4. JVM内存分配策略

JVM内存主要是指运行数据区,粗略的分为:堆、栈,细致区分五部分:方法区、堆、栈、程序计数器、本地方法栈。

(1)程序计数器: 线程私有 ,记录线程所执行的虚拟机字节码指令的地址;如果正在执行的是native方法,这个计数值则为空。唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

(2)Java虚拟机栈: 线程私有,描述Java方法执行的内存模型 : 每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用直至执行完成的过程,就对应这一个栈帧在虚拟机栈中入栈到出栈的过程。栈帧是方法运行时的基础数据结构。如果线程请求栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常;如果虚拟机栈动态扩展时无法申请到足够的内存,抛出 OutOfMemoryError异常。

(3)本地方法栈: 线程私有,描述native方法执行的内存模型。有的虚拟机(如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

(4)Java堆: 线程共享,存放对象实例及数组,是垃圾收集器管理的主要区域 采用分代收集策略,所以Java堆会细分为新生代和老年代。根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上连续的即可。如果堆中没有内存完成实例分配,并且堆也无法再扩展时,抛出OutOfMemoryError异常。

(5)方法区: 线程共享,存储已被虚拟机加载的类信息、常量池、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫Non-Heap(非堆),目的应该是与Java堆区分开来。如果方法区无法满足内存分配需求,抛出OutOfMemoryError异常。对于HotSpot虚拟机,方法区被称为永久代,本质上两者不等价,仅仅是因为HotSpot虚拟机设计团队选择把GC分代收集扩至方法区,或者说使用永久代来实现方法区而已。

JVM堆一般又可以分为以下三部分:Young 新生代、Tenured 老年代、Perm 永久代;

Perm永久代主要保存class,method,filed对象,这部分的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误。

Tenured老年代主要保存生命周期长的对象,多次未被GC掉的对象;

Young新生代主要保存新生成对象,根据JVM的策略,在经过几次垃圾收集后,而没有被垃圾回收的对象将被移动到Tenured区间。有时候该区经常会遇到java.lang.OutOfMemoryError :Java heap space的错误。

-Xms :指定了JVM初始启动以后 初始化内存

-Xmx:指定JVM堆得 最大内存,在JVM启动以后,会分配-Xmx参数指定大小的内存给JVM,但是不一定全部使用,JVM会根据-Xms参数来调节真正用于JVM的内存;

-Xmn:参数设置了新生代的大小;老年代等于-Xmx减去-Xmn;

-XX:Xss:参数设置了永久代的大小;

(6)直接内存: 不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常出现。例如:NIO类,引入了一种基于通道(Channel)与缓冲区(Buffer)的IO方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了Java堆和Native堆中来回复制数据。直接内存虽然不会受到Java堆大小的限制,但是,既然是内存,仍会受到本机总内存大小及处理器寻址空间的限制。

 

(7)JVM参数:-XX:+HeapDumpOnOutOfMemoryError:可让虚拟机在内存溢出异常时Dump出当前的内存堆转储快照以便事后分析;-Xss:设置线程栈大小;-XX:PermSize:设置永久代初始大小;-XX:MaxPermSize:设置永久代最大大小;-XX:MaxDirectMemorySize:设置直接内存大小,默认与Java堆最大值一样;

5. 对象是否可回收

(1) 引用计数算法

存储对特定对象的所有引用数,也就是说,当应用程序创建引用以及引用超出范围时,JVM必须适当增减引用数。当某对象的引用数为0时,便可以进行垃圾收集。

优点:实现简单、效率高

缺点:很难解决对象之间相互引用问题

(2) 可达性分析算法

通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

可作为GC Roots的对象包括:虚拟机栈(栈帧的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI(即一般说的是native方法)引用的对象。

6. 四种引用

(1)强引用:只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

(2)软引用:对软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。

(3)弱引用:对弱引用关联着的对象,只能生存到下一次垃圾收集发生之前。

(4)虚引用:对象是否有虚引用,完全不会对其生存时间构成影响,也无法通过虚引用来取得对象实例。关联虚引用唯一目的就是能在对象被收集器回收时收到系统通知。

7. finalize()方法

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值