Java 虚拟机 垃圾回收机制,堆内存分代存储,类的加载与卸载

==============================================

                                    1:内存模型

==============================================

Java 虚拟机 垃圾回收机制,堆内存分代存储,类的加载与卸载

 

线程共享区域:堆(heap)和 方法区(Method Area)

线程私有:程序计数器,java虚拟机栈,本地方法栈。

堆(heap):new 出来的对象存放位置(存放过大,会导致内存溢出)

方法区:存放静态属性和常量那些(存放过大,会导致内存溢出)

 

程序计数器:可以理解为记录当前线程 执行到哪一行或哪一个指令。以便线程切换回来时,可以从当前指令继续执行。

java虚拟机盏:存放栈帧,可以理解每调用一个方法,就有一个栈帧放进虚拟机盏中,压栈太多会导致栈溢出(也就是方法调用的层级太深)。

本地方法栈:和虚拟机盏类似,但这个栈是用来存放 Native方法时的栈帧。

==============================================

                                    2:内存模块划分

==============================================

 

1:回收算法----  分代收集算法

        【可达性分析算法】标记对象是否需要被回收的算法

        对象引用都是以引用链为路径互相引用。如果一个对象的引用链没有连接上任何 根节点(GC Roots ),那就说明这个对象是没用的,是需要被回收的。所谓的根节点引用,就是:静态属性,常量属性,栈帧引用。 还有 Native方法引用的变量(千万不要说成员变量)的引用。如果没有这四个的引用,即代表这个对象是没用的。

       

         把对象的存活周期分为:新生代老年代

-------新生代 采用 复制算法。(针对对象存活率低使用的算法)

-------------------- 复制算法 :将内存一分为二,分为两个同样大小的区域。每次只用一个区域,等这个区域接近使用完了,会把这个区域的存活对象(可达性分析算法)全部复制到另一个区域,然后把这半个区域全部清空。每次都是对整个半区域进行回收。

                                            缺点:每次只能用半个内存区域,内存空间使用率太低了

                                            优点:效率高,每次只回收半个区域。不用考虑内存碎片的问题,因为复制过后会重新排列,剩余内

                                                       存空间都是完整连续排列的

 

-------老年代 采用   标记-清除算法   或  标记-整理 算法  (针对对象存活率高使用的算法)

--------------------标记-清除 算法:通过可达性分析算法标记需要回收的对象,然后标记后的对象会被GC线程去回收。

                                           缺点1> 效率问题,标记和效率的清楚都不高

                                           缺点2> 空间问题,清除后会产生大量不连续的内存碎片。如果后续要给一个大的对象分配内存空间,这些内存碎片都不足以有足够的空间时,会再次出发GC进行回收。                                      

--------------------标记-整理 算法:通过可达性分析算法标记需要回收的对象,然后标记后的对象会被GC线程去回收。是《标记清除算法》一个加强版。不直接对可回收对象进行清理,而是让存活的对象往一边移动,让所有的存活对象在内存空间里连续排序。然后直接清理掉边界外的无用对象。

                                           优点1> 解决了内存碎片的问题

                                         

---------------------【标记-清除 算法】 示例图

Java 虚拟机 垃圾回收机制,堆内存分代存储,类的加载与卸载

 

---------------------【标记-整理 算法】 示例图

Java 虚拟机 垃圾回收机制,堆内存分代存储,类的加载与卸载

 

2:垃圾回收器--回收机制

垃圾回收器扫到了需要被回收的对象,且这个对象的finalize() 从来没被调用过,会调用对象的 finalize()。如果在finalize()对象重新和根节点连接上(比如:把对象赋值给一个静态变量),那这个时候不会回收这个对象。但如果,对象的finalize() 方法已经被调用过,就不会再调用finalize(),直接就回收了这个对象。

3:内存分配和回收策略

1:分区

新生对象内存分配分为:Eden > Survivor >  老年区    优先级依次递减

新生区:Eden 和 Survivor    (复制回收算法)

老年区:老年区                    (标记-整理回收算法)

 

注意:并不是所有对象都会先在新生区存储的,比如一个对象特别大,就会直接进入 老年区 

所以,避免大对象的创建,会提前触发垃圾回收器去回收垃圾,以提供足够连续的空间去安置大对象。

(java虚拟机可以通过参数设定 大对象的  界限)。超过直接放进老年区。

 

2:对象在内存区域的移动

<规则1>    年龄计数器,每被垃圾回收器扫过一次,年龄就+1。Eden被扫过一次,存活下来就会移到Survivor区域,Survivor区域被扫到15次还存活就会移动老年区。当然,这些界限的参数是可以控制的。

<规则2>    年龄的判断规则不是唯一的。如果Survivor区域所有同龄对象所占内存之和  大于 Survivor空间的一半,那么大于这个年龄的对象都会被移到老年区域。

<规则3>

1>   对象刚开始只会存在于Eden区和Survivor 的 From区,Survivor的“To”是空的。

2>   紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到年龄阈值的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。

3>   Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

Java 虚拟机 垃圾回收机制,堆内存分代存储,类的加载与卸载

 

 

==============================================

                                    2:类加载

==============================================

类的加载分为五大步:

1:加载

1:获取此类的二进制流(分别可以从:zip,网络(applet),运行时才生成(动态代理))

2:将这个流转成方法去运行时的数据结构

3:生成这个类的Class对象,作为此类在方法区的数据访问接口

2:连接

              细分:验证,准备,解析

验证: 验证编码是否符合UTF-8,常量类型是否支持等等这些

准备: 分配内存,初始化变量

解析: 虚拟机将常量池符号引用替换为直接引用

 

3:初始化】   

类加载最后一步

4:使用

使用就是使用对象的属性

5:卸载

卸载,可以理解为引用进程被杀死