内存区域划分 :程序计数器、虚拟机栈、本地方法栈、堆、方法区、运行时常量池
判断对象是否存活—>对象是否原地去世?(finalize()) ->去世 —>如何回收已不再存活的对象
1.引用计数法 2.可达性分析法
finalize()自我拯救
分代回收算法:新生代-复制算法 老年代-标记整理算法
java内存模型 -工作内存 主内存 三大特性:原子性 可见性 有序性
volatile() 1.可见性 2.禁止指令重排
深浅拷贝
一、内存区域划分
线程私有(随着线程的创建而创建,销毁而销毁,生命周期与线程相同,不同线程间隔离)
程序计数器:记录当前线程执行的字节码行号,唯一一块不会产生OOM(内存溢出),本地方法值0
虚拟机栈:Java方法的内存模型
本机方法栈:本地方法的内存模型
线程共享
堆(GC堆):所有对象的实例及数组实例
方法区(JDK8之前永久代):静态变量、常量、加载的类信息
运行时常量池(方法区的一部分):符号引用、字面量
二、垃圾回收器与内存分配策略 (回收针对线程共享内存)
判断对象是否存活—>对象是否原地去世?(finalize()) ->去世 —>如何回收已不再存活的对象
--判断是否存活:
1.引用计数法
缺点:无法解决循环引用问题(Java没有采用它)
2.可达性分析法(JAVA采用)
通过一系列称为GCRoots对象开始向下搜寻,若到指定的对象有路可走("可达"),认为此对象存活,若任意一个GCRoots到目标对象不可达,认为目标对象已经不再存活
GCRoots:1.类中的静态变量、常量 2.栈中的局部变量
************JDK1.2之后关于引用的扩充***********
强引用:程序中普遍存在的类似于Test test = new Test();只要对象被强引用指向,GC无法回收此对象
软引用:描述有用但不必须对象(缓存对象),当对象仅被软引用指向,内存够用不回收,即将发生
OOM,一次性回收掉仅被软引用指向的对象。
弱引用:仅能活到下一次GC之前。GC开始时无论内存是否够用,都会回收掉仅被弱引用指向的对象
虚引用:与对象的生存周期无关,当对象被GC时,由JVM发回一个通知。
--对象是否原地去世?(finalize())
JVM在进行GC之前,需要判断即将回收的对象是否覆写了finalize()?
a.若没有覆写,此对象直接被回收
b.若对象所在类覆写了finalize()
i.若finalize()未被JVM调用,会调用finalize(),若对象在此调用中与GCRoots有路可走,此对
象不会被回收。
ii.若已经调用,此对象直接被回收
final、finally、finalize区别
final:被final修饰的变量的值不能改、修饰的类不能有子类、修饰的方法不能被覆写
finally:用在异常体系中,保证重点代码一定会被执行(流的关闭、socket的关闭)
finalize:Object类提供的一个方法,自我拯救
如何回收已不再存活的对象?
java采用分代回收算法,将内存划分为新生代与老年代,其中新生代采用复制算法,老年代采用记-整理算法
新生代(对象默认在新生代产生,对象存活率较低):复制算法(Eden,Survivor)
老年代(对象存活率较高):标记整理算法
JAVA内存模型
主内存:所有线程共享的内存区域,存放所有的变量(类的实例变量、静态变量、常量)
工作内存:每个线程创建时分配的空间,线程私有,所有变量的读写,均在工作内存中进行
内存模型的三大特性:
原子性:synchronized、lock
可见性:volatile、synchronized、final
有序性:
volatile():
1.具备可见性,当一个线程修改这个变量的值,其他线程能够立即得知此修改
2.禁止指令重排
深浅拷贝
浅拷贝:(牵一发而动全身)拷贝对象内部的引用复用,并不会产生新对象
深拷贝: 拷贝对象内部的引用也会产生新对象
1.递归实现cloneable接口
2.使用序列化(推荐)