周志明先生写的深入理解jvm
我们都知道Java源文件,通过编译器,能够生产相应的.Class文件,也就是字节码文件(由 0和1组成的),而字节码文件又通过Java虚拟机中的解释器,编译成特定机器上的机器码 。
也就是如下:
① Java源文件—->编译器—->字节码文件
② 字节码文件—->JVM—->机器码
每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是Java为什么能够跨平台的原因了
JVM执行程序的过程:将字节码文件加载至内存中
- 加载class文件
- 管理并分配内存
- 执行垃圾收集
Java中加载器的种类大致可以分为四种:
引导类加载器(bootstrap class loader)
扩展类加载器(extensions class loader)
应用程序类加载器(application class loader)
自定义类加载器
ClassLoader:类加载器(class loader)用来加载 class文件到 Java 虚拟机中。Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。
虚拟机栈:用来存栈帧的,对象的引用。随着线程结束内存就释放,不需要垃圾回收。
内存溢出,通过减小最大堆和栈容量来换取更多的线程。
堆:用来存放对象的,几乎所有对象都放在这里,被线程/栈共享
堆也是垃圾回收的主要区域,又叫GC堆
存放被NEW出来的对象
方法区:方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。该区域是被线程共享的。
程序计数器:是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。程序中的分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。
本地方法栈:和虚拟机栈一样,但是只为本地方法服务
堆he 栈区别:
堆:堆空间一般由程序员来分配,可以由垃圾回收机制来回收。一般用来存放new创建的对象和数组。
栈:栈是“后进先出”的存储空间,一般用来存储基本类型的数据和对象的引用。
类加载器双亲委派模型机制?
当一个类收到了类加载请求时,不会自己先去加载这个类,而是将其委派给父类,由父类去加载,如果此时父类不能加载,反馈给子类,由子类去完成类的加载。
类加载的五个过程:加载、验证、准备、解析、初始化
如和判断一个对象是否存活?(或者GC对象的判定方法)
引用计数法:根据当前对象是否存在引用来判断,如果引用为0,那么就直接回收.
可达性算法(引用链法):从一个被称为GC Roots的对 象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。
垃圾回收器(三种方法:标记清除、标记整理、复制算法):
CMS收集器是基于“标记—清除”算法实现的,时间快,响应快,会产生碎片
G1从整体来看是基于“标记—整理”算法实现的收集器,是基于“复制”算法实现的
响应优先选择CMS,吞吐量高选择G1
Serial收集器:是一个单线程的收集器,只会使用一个CPU或一条收集线程去完成垃圾收集工作,在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
JVM垃圾回收机制
JVM中共划分为三个代:年轻代、年老代和持久代
年轻代:存放所有新生成的对象;
年老代:在年轻代中经历了N次垃圾回收仍然存活的对象,将被放到年老代中,故都是一 些生命周期较长的对象;
持久代:用于存放静态文件,如Java类、方法等。
其中用System.gc()强制执行的是年老态.
触发GC(Garbage Collector)的条件:
1.GC在优先级最低的线程中运行,一般在应用程序空闲即没有应用线程在运行时被调用。 2.Java堆内存不足时,GC会被调用。
jvm中一次完整的GC流程(从ygc到fgc)是怎样的,对象如何晋升到老年代等 对象优先在新生代区中分配,若没有足够空间,启动Minor GC垃圾回收;
大对象(需要大量连续内存空间)直接进入老年态;长期存活的对象进入老年态。如果对象在新生代出生并经过第一次Minor GC后仍然存活,年龄+1,若年龄超过一定限制(15),则被晋升到老年态
1、内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
2、内存溢出 out of memory :指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
JVM调优
设定堆内存大小-Xms
查看堆空间大小分配(年轻代、年老代、持久代分配)
垃圾回收监控(长时间监控回收情况)
线程信息监控:系统线程数量
线程状态监控:各个线程都处在什么样的状态下
线程详细信息:查看线程内部运行情况,死锁检查
CPU热点:检查系统哪些方法占用了大量CPU时间
内存热点:检查哪些对象在系统中数量最大
Java的反射机制
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法
对于任意一个对象,都能调用其任意一方法。
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射可以将.class文件转为.java文件,实现反编译
反射中 Class.forName 和 ClassLoader 区别:
一般情况下,这两个方法效果一样,都能装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。