JVM-GC-异常

?9、JVM
1、JVM回收算法和回收器,CMS采用哪种回收算法,怎么解决内存碎片问题?

复制算法:两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最常用的算法
标记清理:一块区域,标记可达对象(可达性分析),然后回收不可达对象,会出现碎片问题
标记-整理算法:多了碎片整理,整理出更大的内存放更大的对象
两个概念:新生代和年老代
新生代:初始对象,生命周期短的
永久代:长时间存在的对象
整个java的垃圾回收是新生代和年老代的协作,这种叫做分代回收。
P.S:Serial New收集器是针对新生代的收集器,采用的是复制算法
Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理
Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法
Serial Old(串行)收集器,新生代采用复制,老年代采用标记整理
Parallel Old(并行)收集器,针对老年代,标记整理
CMS收集器,基于标记清理
G1收集器:整体上是基于标记 整理 ,局部采用复制

综上:新生代基本采用复制算法,老年代采用标记整理算法。cms采用标记清理。

2、类加载过程

在这里插入图片描述

加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。以下陈述的内容都已HotSpot为基准。

加载
在加载阶段(可以参考java.lang.ClassLoader的loadClass()方法),虚拟机需要完成以下3件事情:

通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
加载阶段和连接阶段(Linking)的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。

验证
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
验证阶段大致会完成4个阶段的检验动作:

文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以魔术0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
符号引用验证:确保解析动作能正确执行。
验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:

            publicstaticintvalue=123;        

那变量value在准备阶段过后的初始值为0而不是123.因为这时候尚未开始执行任何java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器()方法之中,所以把value赋值为123的动作将在初始化阶段才会执行。
至于“特殊情况”是指:public static final int value=123,即当类字段的字段属性是ConstantValue时,会在准备阶段初始化为指定的值,所以标注为final之后,value的值在准备阶段初始化为123而非0.

解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

初始化
类初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的java程序代码。在准备极端,变量已经付过一次系统要求的初始值,而在初始化阶段,则根据程序猿通过程序制定的主管计划去初始化类变量和其他资源,或者说:初始化阶段是执行类构造器()方法的过程.
()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块static{}中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问

3、JVM分区

1、java堆(线程共享):java虚拟机所管理的内存中最大的一块,存放对象实例。

2、方法区(线程共享):存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区中最重要的是运行时常量池,常量池中存放编译期生成的各种字面量和符号引用。

3、java虚拟机栈(线程私有):为java方法服务,栈元素是栈帧,当有一个方法被调用时,这个方法的栈帧入栈,当这个方法返回时,栈帧出栈。栈帧中包括局部变量表(包括方法的参数和方法内部定义的变量),操作数栈(例如将局部变量i赋值为0,需要先将0入栈,再赋值给i),动态链接(子类实例化父类,只有在真正运行时,才知道调用的是哪个类的方法),出口(处理正常return和产生异常的情况)。

4、本地方法栈(线程私有):功能与java虚拟机栈类似,但是java虚拟机栈是为java方法服务,本地方法栈是为Native服务。

5、程序计数器(线程私有):每个线程都有一个程序计数器,用作指示当前线程所执行字节码的行号。取下一条需要执行的字节码指令(循环跳转等)、线程恢复(当前线程时间片用完,另一个线程执行,当前线程被挂起,当重新唤醒此线程时,根据程序计数器来继续执行字节码)等都需要依赖这个计数器来完成。

4、eden区,survial区?

新生代有一个较大的Eden区和两个较小的Survivor区组成,绝大多数新创建的对象都是在Eden区分配的,其中大多数对象很快消亡。Eden是一块连续的内存,所以分配内存的速度很快。
首先,Eden满时,进行一次minor gc ,将存活 的对象复制到 To Survivor(以下简称To),清除Eden消亡的对象。当Eden再次满时,进行minor gc,To中能够晋升的移动到老年代,存活的对象复制到From。
清空Eden和To,如此切换(默认15),将存活的对象迁移到老年代。*

5、JAVA虚拟机的作用?

  • 通过 ClassLoader 寻找和装载 class 文件
  • 解释字节码成为指令并执行,提供 class 文件的运行环境
  • 进行运行期间垃圾回收
  • 提供与硬件交互的平台

6、GC中如何判断对象需要被回收?

  • gc用到垃圾回收机制算法,判断是否是垃圾,从而进行回收。
  • 引用可达法法,程序运行从开始,每次引用对象,都将对引用的对象进行连接起来,到最后形成一张网,没有在这张网上的对象则被认为是垃圾对象。
  • 引用计数法,对于对象的引用,每引用一次计数器加一,引用失败,计数器减一,当计数器一段时间为0,则可以被认为是垃圾。

7、JAVA虚拟机中,哪些可作为ROOT对象?

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 静态变量引用的变量
  • 方法区常量引用的变量
  • 本地方法栈中引用的变量

9、jvm是如何实现线程?

java虚拟机的多线程是通过线程轮流切换分配处理执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条程序中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。

简单点说,对于单核处理器,是通过快速切换线程执行指令来达到多线程的,因为单核处理器同时只能处理一条指令,只是这种切换速度很快,我们根本不会感知到。

**

10、jvm最大内存限制多少

Jessidea
这个如果不使用-xx:Xmx -xx:Xms -xx:Permsize -xx:MaxPermsize参数进行设置的话,应该和不同版本的jdk的jvm最大内存限制相关吧。
公司 JVM版本 最大内存(兆)client 最大内存(兆)server

SUN 1.5.x 1492 1520

SUN 1.5.5(Linux) 2634 2660

SUN 1.4.2 1564 1564

SUN 1.4.2(Linux) 1900 1260

IBM 1.4.2(Linux) 2047 N/A

BEA JRockit 1.5 (U3) 1909 1902

11、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?

  • java源程序(.java)被编译器编译成字节码文件(.class)。然后字节码文件,将由java虚拟机,解释成机器码(不同平台的机器码不同)。利用机器码操作硬件和操作系统
  • 因为不同的平台装有不同的JVM,它们能够将相同的.class文件,解释成不同平台所需要的机器码。正是因为有JVM的存在,java被称为平台无关的编程语言

12、描述一下JVM加载class文件的原理机制?

委托机制,可见性机制,单一性机制 父类静态代码块,子类静态代码块,父类构造代码块和构造方法,子类构造代码块和构造方法。 启动类加载器,扩展类加载器,应用程序类加载器。

❤10、GC

1、java中内存泄露是啥,什么时候出现内存泄露?

  • 长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收
  • 引起内存泄露的原因:
      (1)静态集合类,例如HashMap和Vector。如果这些容器为静态的,由于它们的生命周期与程序一致,那么容器中的对象在程序结束之前将不能被释放,从而造成内存泄露。
      (2)各种连接,例如数据库连接、网络联接以及IO连接等。在对数据库进行操作的过程中,首先需要建立与数据库的连接、当不再使用时,需要调用close方法来释放与数据库的连接。只有连接被关闭后,垃圾回收器才会回收对应的对象。否则,如果在访问数据库的过程中,对Connection、Statement或ResultSet不显示地关闭,将会造成大量的对象无法被回收,从而引起内存泄露。
      (3)监听器。在Java语言中,往往会使用到监听器。通常一个应用中会用到多个监听器。但在释放对象的同时往往没有相应地删除监听器,这也可能导致内存泄露。
      (4)变量不合理的作用域。一般而言,如果一个变量定义的作用范围大于其使用范围,很有可能会造成内存泄露,另一方面如果没有及时地把对象设置为null,很有可能会导致内存泄露的发生。

2、minor gc如果运行的很频繁,可能是什么原因引起的,minor gc如果运行的很慢,可能是什么原因引起的?

  • minor gc运行的很频繁可能是什么原因引起的?
    1、 产生了太多朝生夕灭的对象导致需要频繁minor gc
    2、 新生代空间设置的比较小
  • minor gc运行的很慢有可能是什么原因引起的? 1、 新生代空间设置过大。
    2、 对象引用链较长,进行可达性分析时间较长。
    3、 新生代survivor区设置的比较小,清理后剩余的对象不能装进去需要移动到老年代,造成移动开销。
    4、 内存分配担保失败,由minor gc转化为full gc
    5、 采用的垃圾收集器效率较低,比如新生代使用serial收集器

3、阐述GC算法

GC算法分成四种:

  • 标记清除算法:首先先标记,然后统一把标记的对象依次清除,缺点是CPU消耗大,极易出现内存碎片,所以一般用于老年代。
  • 复制算法:把内存区域分成俩块,每次只使用其中一块,然后把还存活的对象放在另一块中,清空原先的块,这样的话不会出现内存碎片。新生代常用的。
  • 复制整理:指针碰撞,将使用过的对象移动到内存的一段,不用的放在另一端。
  • 分代收集:根据不同代的区别,使用符合不同代的算法。
  • 简单来说minorGC发生在新生代,频繁而且需要开销小,所以采取复制算法。
    老年代:对象相较于新生代gc不频繁且对象少,采取标记清除或者标记整理算法。

4、GC是什么? 为什么要有GC?

garbage collection 中文名叫垃圾回收机制 。GC的作用在于回收程序中由编码人员从堆中申请的内存 减少内存泄漏的可能

6、java中会存在内存泄漏吗,请简单描述。
不对,首先java在内存分配不当的情况下,也会出现内存泄露。
长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收

7、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?(垃圾回收)

  • 1、对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。
    通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。
    2、可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

❤11、异常体系

2、运行时异常与一般异常有何异同?

  • Java提供了两类主要的异常:runtime exception和checked exception。checked
    异常也就是我们经常遇到的IO异常,以及SQL异常都是这种异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。
  • 但是另外一种异常:runtime
    exception,也称运行时异常,我们可以不处理。当出现这样的异常时,总是由虚拟机接管。比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。
  • 出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有一般异常的特点,是可以被Catch块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。
  • 如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常,或者是通过对异常的处理显式的控制程序退出。

3、error和exception有什么区别?

首先Exception和Error都是继承于Throwable 类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。

Exception和Error体现了JAVA这门语言对于异常处理的两种方式。

Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。

Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。

其中的Exception又分为检查性异常和非检查性异常。两个根本的区别在于,检查性异常 必须在编写代码时,使用try catch捕获(比如:IOException异常)。非检查性异常 在代码编写使,可以忽略捕获操作(比如:ArrayIndexOutOfBoundsException),这种异常是在代码编写或者使用过程中通过规范可以避免发生的。

4、给我一个你最常见到的runtime exception
Java.lang.NullPointerException空指针异常
Java.lang.IndexOutOfBoundsException索引超出异常
Java.lang.ArithmeticException算术异常
Java.lang.ClassCastException类转换异常
IllegalArgumentException非法数据异常
IllegalStateException非法语句异常

5、Java中的异常处理机制的简单原理和应用。

java异常处理机制可以从两个方面来描述,当一个java程序违反了java语义的时候,JVM虚拟机就会抛出一个异常,比如说当遇到的null的时候,会抛出一个nullpointExcepiton,当遇到下标越界的时候就会抛出indexoutofbroundsException,除此之外,程序员还可以自定义异常,去拓展这种语义的检查,并在合适的时机,通过throw关键字抛出异常。其中,try{}是监控的代码语句块,catch{}是处理异常,finally{}语句块无论是否发生异常都会执行。

6、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?

答:字节流,字符流。
字节流继承于InputStream OutputStream,
字符流继承于Reader Writer。
在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。

7、什么是java序列化,如何实现java序列化?

  • 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。
    可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。 序列化是为了解决在对对象流进行读写操作时所引发的问题。
  • 序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法, implements
    Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造
    一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object
    obj)方法就可以 将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值