Java-中的强引用软引用弱引用虚引用以及-GC-策略

在介绍各种引用之前,先简单介绍下垃圾回收 什么是垃圾回收垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。Java 语言出来之前,大家都在拼命的写 C 或者 C++ 的程序,而此时存在一个很大的矛盾,C++ 等语言创建对象要不断的去开辟空间,不用的时候又需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都在重复的 allocated,然后不停的析构。于是,有人就提出,能不能写一段程序实现这块功能,每次创建,释放控件的时候复用这段代码,而无需重复的书写呢?1960年,基于 MIT 的 Lisp 首先提出了垃圾回收的概念,用于处理C语言等不停的析构操作,而这时 Java 还没有出世呢!所以实际上 GC 并不是Java的专利,GC 的历史远远大于 Java 的历史!Java中的垃圾回收是根据可达性分析算法来判断对象是否存活的 可达性分析算法在主流的商用程序语言(Java、C#,甚至包括前面提到的古老的Lisp)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如图3-1所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。 在Java语言中,可作为GC Roots的对象包括下面几种: 虚拟机栈(栈帧中的本地变量表)中引用的对象。方法区中类静态属性引用的对象。方法区中常量引用的对象。本地方法栈中JNI(即一般说的Native方法)引用的对象。各种引用对象是否存活与“引用”有关。 在JDK 1.2以前,Java中的引用的定义很传统:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。这种定义很纯粹,但是太过狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态,对于如何描述一些“食之无味,弃之可惜”的对象就显得无能为力(这里说的就是强引用,最基本的引用方式)。 我们希望能描述这样一类对象:当内存空间还足够时,则能保留在内存之中;如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。很多系统的缓存功能都符合这样的应用场景。 在JDK 1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。 引用类型GC策略简介强引用(Strong Reference)永远不会回收(GC ROOT可引用到的前提下)最基本的引用Object obj=new Object()软引用(Soft Reference)OOM之前回收SoftReference弱引用(Weak Reference)下一次GC前WeakReference虚引用(Phantom Reference)未知,也就是随时可能被回收PhantomReference强引用强引用就是最基本的引用方式,Object obj=new Object(),引用的是另一块内存的起始地址。强引用的对象回收基于“可达性分析”算法,当对象不可达时才可能会被回收。 比如方法中new的对象,引用赋值给方法内的局部变量(局部变量存储在栈帧中的局部变量表),当方法结束之后,栈帧出栈,对象就自然不可达了,不可达就可能会被回收 软引用软引用是用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用。SoftReference<RefObj> ref = new SoftReference<RefObj>(refObj);写个例子来测试下软引用的GC策略: # JVM OPTIONS: -XX:+PrintGCDetails -Xmx5mpublic class ReferenceTest { private List<RefObj> refObjs = new ArrayList<>(); private SoftReference<RefObj> ref = new SoftReference<RefObj>(createRefObj(4096*256));//1m public void add(){ refObjs.add(createRefObj(4096)); } private RefObj createRefObj(int dataSize){ RefObj refObj = new RefObj(); byte[] data = new byte[dataSize]; for (int i = 0; i < dataSize; i++) { data[i] = Byte.MAX_VALUE; } refObj.setData(data); return refObj; } public void validRef(){ System.out.println(ref.get()); } public static void main(String[] args) { ReferenceTest referenceTest = new ReferenceTest(); for (int i = 0; i < 1200; i++) { //不停新增堆大小 referenceTest.add(); //新增后查看SoftReference中的对象是否被回收 referenceTest.validRef(); } } private class RefObj{ private byte[] data; public byte[] getData() { return data; } public void setData(byte[] data) { this.data = data; } }}ReferenceTest中维护一个RefObjList和一个SoftReference,往RefObjList不断添加对象,增加堆大小,直至内存溢出。来观察下SoftReference中引用的对象是否还存在 ...

October 7, 2019 · 4 min · jiezi

深入理解 lambda表达式 与 MethodReference(四)

package com.java.design.java8.MethodReference;import com.java.design.java8.entity.Student;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.Arrays;import java.util.List;import java.util.function.Supplier;/** * @author 陈杨 */@RunWith(SpringRunner.class)@SpringBootTestpublic class MethodReference {一、测试数据准备private List<Student> students;private List<String> snames;private Student studentSupplier(Supplier<Student> studentSupplier) { return studentSupplier.get();}// private StudentConstructor studentConstructor =// (id, name, sex, age, addr, salary) ->// new Student(id, name, sex, age, addr, salary);private StudentConstructor studentConstructor = Student::new;private Student studentAllArgs(Integer id, String name, String sex, Integer age, String addr, Double salary) { return studentConstructor.studentAllArgs(id, name, sex, age, addr, salary);}@Beforepublic void init() { Student kirito = new Student(1, “Kirito”, “Male”, 18, “Sword Art Online”, 999999999.0); Student Asuna = new Student(2, “Asuna”, “Female”, 17, “Sword Art Online”, 999999999.0); Student Sinon = new Student(3, “Sinon”, “Female”, 16, “Gun Gale Online”, 999999999.0); Student Yuuki = new Student(4, “Yuuki”, “Female”, 15, “Alfheim Online”, 999999999.0); Student Alice = new Student(5, “Alice”, “Female”, 14, “Alicization”, 999999999.0); students = Arrays.asList(kirito, Asuna, Sinon, Yuuki, Alice); snames = Arrays.asList(“kirito”, “Asuna”, “Sinon”, “Yuuki”, “Alice”);}二、方法引用 引入@Testpublic void testMethodReference() { // MethodReference 方法引用 List<String> Iloveyou = Arrays.asList(“Kirito”, “Love”, “Asuna”); //集合遍历 Lambda System.out.println("—————————————\n"); System.out.println(“集合遍历 Lambda”); Iloveyou.forEach(str -> System.out.println(str)); //集合遍历 MethodReference System.out.println("—————————————\n"); System.out.println(“集合遍历 MethodReference”); Iloveyou.forEach(System.out::println);三、什么是方法引用// MethodReference// 方法引用是Lambda表达式的特殊替换// 方法引用本质是一个 函数指针 Function Pointer// 这个指针指向被引用方法// eg: 方法引用System.out::println 指向System.out.println()这个函数四、方法引用的分类1、 静态方法引用// 1、 静态方法引用// 静态方法引用 类名::静态方法名// 静态方法引用 功能实现等价于 调用 类的静态方法// 静态方法引用 与 调用 无任何关系// 类名.静态方法名 –>方法调用 显示传参// 类名::静态方法名 –>方法引用 隐式传参 编译器自动推断 方法引用的表达式 函数指针 指向 被引用函数System.out.println("—————————————\n");System.out.println(" 静态方法引用 按年龄排序");students.sort(StaticStudentComparator::staticCompareStudentByAge);students.forEach(System.out::println);System.out.println("—————————————\n");System.out.println(" 静态方法引用 按姓名排序");students.sort(StaticStudentComparator::staticCompareStudentByName);students.forEach(System.out::println);2、 对象实例方法引用// 2、 对象实例方法引用// 对象实例方法引用 引用名(对象名)::实例方法名// 对象实例方法引用 功能实现等价于 调用 对象实例 所拥有的 实例方法StudentComparator studentComparator = new StudentComparator();System.out.println("—————————————\n");System.out.println(" 静态方法引用 按年龄排序");students.sort(studentComparator::compareStudentByAge);students.forEach(System.out::println);System.out.println("—————————————\n");System.out.println(" 对象实例方法引用 按姓名排序");students.sort(studentComparator::compareStudentByName);students.forEach(System.out::println);3、 类实例方法引用// 3、 类实例方法引用// 类实例方法引用 类名::实例方法名System.out.println("—————————————\n");System.out.println(" 类实例方法引用 按年龄排序");students.sort(Student::classCompareStudentByAge);students.forEach(System.out::println);System.out.println("—————————————\n");System.out.println(" 类实例方法引用 按姓名排序");students.sort(Student::classCompareStudentByName);students.forEach(System.out::println);System.out.println("—————————————\n");System.out.println(" 类实例方法引用 容易理解的 字符串排序");snames.sort(String::compareToIgnoreCase);snames.forEach(System.out::println);4、 构造方法引用// 4、 构造方法引用// 构造方法引用 类名::new// 注意: 实体类Student 事先 有定义好的 全参构造方法 与无参构造方法// 若没有构造方法 需要自行添加 否则报错// Student::new 可以根据参数不同 对构造方法进行自动识别 重载// 利用无参构造方法构造studentNoArgs对象System.out.println("—————————————\n");System.out.println(“利用无参构造方法构造studentNoArgs对象”);Student studentNoArgs = this.studentSupplier(Student::new);System.out.println(studentNoArgs);// 利用自定义全参构造方法构造student对象System.out.println("—————————————\n");System.out.println(“利用全参构造方法构造studentNoArgs对象”);Student Silica = this.studentAllArgs (6, “Silica”, “Female”, 10, “Sword Art Online”, 999999999.0);System.out.println(Silica); }}五、StaticStudentComparator类 (静态方法实例引用)import com.java.design.java8.entity.Student;import java.util.Comparator;public class StaticStudentComparator { static Comparator<Student> studentAgeComparator = (first, last) -> first.getAge() - last.getAge(); static Comparator<Student> studentNameComparator = (first, last) -> first.getName().compareToIgnoreCase(last.getName()); public static int staticCompareStudentByAge(Student first, Student last) { return studentAgeComparator.compare(first, last); } public static int staticCompareStudentByName(Student first, Student last) { return studentNameComparator.compare(first, last); }}六、StudentComparator类 (对象方法实例引用)import com.java.design.java8.entity.Student;import java.util.Comparator;public class StudentComparator { Comparator<Student> studentAgeComparator = (first, last) -> first.getAge() - last.getAge(); Comparator<Student> studentNameComparator = (first, last) -> first.getName().compareToIgnoreCase(last.getName()); public int compareStudentByAge(Student first, Student last) { return studentAgeComparator.compare(first, last); } public int compareStudentByName(Student first, Student last) { return studentNameComparator.compare(first, last); }}七、StudentConstructor @FunctionalInterface接口 (构造方法实例引用)import com.java.design.java8.entity.Student;@FunctionalInterfacepublic interface StudentConstructor { Student studentAllArgs(Integer id, String name, String sex, Integer age, String addr, Double salary);}八 、Student实体类 (类实例方法引用)@Data@AllArgsConstructor@NoArgsConstructorpublic class Student { private Integer id; private String name; private String sex; private Integer age; private String addr; private Double salary; public int classCompareStudentByAge(Student student) { return this.getAge() - student.getAge(); } public int classCompareStudentByName(Student student) { return this.getName().compareToIgnoreCase(student.getName()); }}九、 测试结果 . ____ _ __ _ _ /\ / ’ __ _ () __ __ _ \ \ \ ( ( )__ | ‘_ | ‘| | ‘ / ` | \ \ \ \ \/ )| |)| | | | | || (| | ) ) ) ) ’ || .__|| ||| |_, | / / / / =========||==============|/=//// :: Spring Boot :: (v2.1.2.RELEASE)2019-02-02 17:04:20.851 INFO 16876 — [ main] c.j.d.j.MethodReference.MethodReference : Starting MethodReference on DESKTOP-87RMBG4 with PID 16876 (started by 46250 in E:\IdeaProjects\design)2019-02-02 17:04:20.852 INFO 16876 — [ main] c.j.d.j.MethodReference.MethodReference : No active profile set, falling back to default profiles: default2019-02-02 17:04:21.422 INFO 16876 — [ main] c.j.d.j.MethodReference.MethodReference : Started MethodReference in 0.878 seconds (JVM running for 1.682)—————————————集合遍历 LambdaKiritoLoveAsuna—————————————集合遍历 MethodReferenceKiritoLoveAsuna————————————— 静态方法引用 按年龄排序Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)Student(id=4, name=Yuuki, sex=Female, age=15, addr=Alfheim Online, salary=9.99999999E8)Student(id=3, name=Sinon, sex=Female, age=16, addr=Gun Gale Online, salary=9.99999999E8)Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8)Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)————————————— 静态方法引用 按姓名排序Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8)Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)Student(id=3, name=Sinon, sex=Female, age=16, addr=Gun Gale Online, salary=9.99999999E8)Student(id=4, name=Yuuki, sex=Female, age=15, addr=Alfheim Online, salary=9.99999999E8)————————————— 静态方法引用 按年龄排序Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)Student(id=4, name=Yuuki, sex=Female, age=15, addr=Alfheim Online, salary=9.99999999E8)Student(id=3, name=Sinon, sex=Female, age=16, addr=Gun Gale Online, salary=9.99999999E8)Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8)Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)————————————— 对象实例方法引用 按姓名排序Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8)Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)Student(id=3, name=Sinon, sex=Female, age=16, addr=Gun Gale Online, salary=9.99999999E8)Student(id=4, name=Yuuki, sex=Female, age=15, addr=Alfheim Online, salary=9.99999999E8)————————————— 类实例方法引用 按年龄排序Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)Student(id=4, name=Yuuki, sex=Female, age=15, addr=Alfheim Online, salary=9.99999999E8)Student(id=3, name=Sinon, sex=Female, age=16, addr=Gun Gale Online, salary=9.99999999E8)Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8)Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)————————————— 类实例方法引用 按姓名排序Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8)Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)Student(id=3, name=Sinon, sex=Female, age=16, addr=Gun Gale Online, salary=9.99999999E8)Student(id=4, name=Yuuki, sex=Female, age=15, addr=Alfheim Online, salary=9.99999999E8)————————————— 类实例方法引用 容易理解的 字符串排序AliceAsunakiritoSinonYuuki—————————————利用无参构造方法构造studentNoArgs对象Student(id=null, name=null, sex=null, age=null, addr=null, salary=null)—————————————利用全参构造方法构造studentNoArgs对象Student(id=6, name=Silica, sex=Female, age=10, addr=Sword Art Online, salary=9.99999999E8) ...

February 2, 2019 · 4 min · jiezi