java学习(5),JVM内存模型以及GC回收算法

1.JVM的作用

java源文件通过编译器,能够产生对应的class文件,也就是字节码文件。这个字节码文件通过JVM中的计时器,编译成机器码。最终实现的目的是能够不区分平台而去执行,不论是linux,windows平台,并且也不论传入的java程序还是c程序,只要生成了class文件。最终都会转换成机器码。这也就是为什么java能够跨平台的原因,个人理解:JVM类似于像是操作系统一样的东西,操作系统是用来封装软件和硬件,而JVM是封装语言和平台。

2.JVM的内存结构

JVM包含方法区,java堆,java虚拟机栈,本地方法区栈,指令计数器以及其他隐含的寄存器。
java学习(5),JVM内存模型以及GC回收算法
方法区:是线程共享的,存储编译后的java代码和符号表。存放了要加载的类信息、静态变量、final类型的变量、属性和方法信息。JVM用持久代(永久代)来存放方法区。
java堆:是线程共享的,分配内存的最主要的地方。所有通过new创建的对象的内存都在堆中。同时也是GC最主要工作的地方。通过Gc的机制来看,整个java堆可以分为新生代和老生代,新生代中又分为eden区(伊甸园),survivor0 survivor1 。申请内存的时候优先从eden中分配。
java虚拟机栈:是线程私有的,在线程创建的同时产生,每个方法执行的同时都会创建一个帧栈用来存储方法的变量表、操作数栈,动态链接方法,返回值和返回地址等信息。栈的大小决定了递归的深度。如果超出了栈的深度那么抛出*异常,如果没有内存空间支持扩展,那么抛出OutOfMemeryError.
本地方法区:线程私有的。管理本地方法,C语言的方法。
指令计数器:线程独立的,记录当前线程执行到了哪条指令,并且记录下一条的指令.

3.类的加载原理

什么是类加载?
类加载是指将类的.class文件中的二进制数据读入到内存中,将其放入运行时数据区的方法区内,然后在堆区创建一个java.lang.class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的class对象。class对象封装了类在方法区内的数据结构。并向java程序员提供了访问方法区内的数据结构的接口。类加载器并不需要等到某个类被首次使用时才加载它,jvm规范允许在预料到某个类有可能要开始加载的时候就进行预先加载,如果在预加载的过程中遇到了.class文件缺失或者文件错误。类加载器必须在程序首次使用这个类的时候才报错。如果一直不使用这个类,那么不报错。

1.类加载器

在进行类加载流程的时候,首先要介绍一下什么是类加载器。当一个JVM启动的时候,java缺省开始使用如下三种类型的类装入器。
启动类加载器(Bootstrap Class Loader):
扩展类加载器(Extension Class Loader):ExtClassLoader
系统类加载器(System Class Loader):AppClassLoade

2.双亲委派机制

这么写的类加载器之间是什么关系呢?加载类的时候是怎么配合的呢?
JVM在加载类的时候默认使用双亲委派机制:某个类加载器在收到加载类的任务的时候,优先传送给自己的父类加载器。如果父类可以加载,那么成功返回。如果父类不能完成,那么自己加载。
类加载器之间的关系如图:
java学习(5),JVM内存模型以及GC回收算法

3.类加载机制:

1.装载,2.链接(验证,准备,解析) 3.初始化 这五个阶段是按照顺序开始(解析阶段的顺序不确定,有可能在初始化之后,为了支持运行时绑定),却不一定按照顺序结束,因为这些阶段通常都是交互着进行的。通常在执行一个的过程中就触发另一个阶段。
1.加载—->查找并加载类的二进制数据:
加载是加载类的第一个阶段,在这个阶段虚拟机有如下动作:
1.通过一个类的全限定名,来获取这个类的二进制流。
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3.在java堆中生成一个代表这个类的class对象,作为对方法区中数据访问的入口。
2.链接—–>分为验证,准备,解析
1.验证——–>确保被加载类的正确性。
2.准备——–>为类的静态变量分配内存,并将其初始化为默认值。
3.解析——–>把类中的符号引用换成直接饮用。
3.初始化—->

3.Gc

1.GC的时机:

Gc的时机是不确定的,也就是并不能确定发生垃圾回收的时间,可以通过System.gc来尝试出发一次Gc。但是不一定能成功。Gc分为Minor Gc和FullGc。MinorGc指在新生代中发生的垃圾回收,FullGc指的是不只在新生代也在老生代发生垃圾回收。清理整个的堆空间。当Eden区慢的时候就会进行一次MinorGc。
Gc的方法:可到达,复制算法新生代,压缩算法老生代。