引用(绳子)
引用计数算法
原理:给对象中每一个对象分配一个引用计数器,每当有地方引用该对象时,引用计数器的值加一,当引用失效时,引用计数器的值减一,不管什么时候,只要引用计数器的值等于0了,说明该对象不可能再被使用了。就会被回收(GC) 绳子计数器被绳子套上了就加个一
优点:实现原理简单,而且判定效率很高。大部分情况下都是一个不错的算法。
缺点:很难解决对象之间相互循环引用的问题,例如:对象A和对象B都有instance字段,并且A.instance=B,并且B.instance=A,即使这两个对象再无任何其他引用,并且已经不可能再被访问,引用计数器的值也为0了,这两个对象也是不可能再被使用了,此时引用计数器算法也无法通知GC来回收这两个对象 (类比死锁)
枚举根节点做可达性分析
四种GCRoots对象:
1、虚拟机栈(栈帧中的局部变量区)
2、方法区中的类静态属性引用的对象
3、方法区中常量引用的对象
4、本地方法栈JNI引用的对象
方法区的回收
垃圾收集主要回收两部分内容:废弃常量和无用的类 回收废弃常量与回收Java堆中的对象非常类似。以常量池中字面量的回收为例,假如一个字符串“abc”已经进入了常量池中,但是当前系统没有任何一个String对象是叫做“abc”的,换句话说是没有任何String对象引用常量池中的“abc”常量,也没有其他地方引用了这个字面量,如果在这时候发生内存回收,而且必要的话,这个“abc”常量就会被系统“请”出常量池。
判定一个类是否是无用类,需要满足三个条件:
1、该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
2、加载该类的ClassLoader已经被回收。
3、该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
强引用
编写的代码95%都是强引用
默认支持 百分之九十五都是强引用,当内存不足,JVM开始垃圾回收 ,对于强引用的对象,就算是抛出OOM,也不会对该对象进行回收。强引用是造成Java内存泄露的最主要原因之一。
对于一个普通对象,如果没有其他引用关系,只要超过了引用的作用域(局部变量)或者显示的将相应的引用赋值为null,一般就认为可以被垃圾收集了。
软引用
内存充足 不回收,内存不足 回收。
需要用java.lang.ref.SoftReference类实现 一般用来做(JVM中缓存)缓存 内存够用 不回收 不够用就回收
使用场景:
假如一个应用需要读取大量的本地图片:
-
如果每次读取图片都从硬盘读取,则会严重影响性能
-
如果一次性全部加载到内存中,有可能造成内存溢出
此时,可以使用软引用解决这个问题 够就存再内存只有内存不够时才会回收
弱引用
在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。需要用java.lang.ref.WeakReference类实现
谈谈WeakHashMap的理解。
map的toString方法会转为{1=hello world}
`System.out.println(map)`输出`{1=hello world}`是因为`map`对象的`toString()`方法被调用了。
在Java中,当我们直接将一个对象传递给`System.out.println()`方法时,实际上会调用对象的`toString()`方法将其转换为字符串进行输出。对于`Map`对象来说,`toString()`方法会按照`{key1=value1, key2=value2, ...}`的格式将其内容转换为字符串。
在你的例子中,`map`对象是一个`Map<Integer, String>`类型的对象,其中键`1`对应的值是`hello world`。
WeakHashMap(弱哈希map),只要一起用GC垃圾回收,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
虚引用
referenceQueue.poll() 回收站的放与拿
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue回收站)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
不足溢出oom,强引用会导致泄露