副问题[/!--empirenews.page--]
之前我们提到过 GC,但当 Java 中引用的工具越来越多,会导致内存空间不敷,最终会发生错误 OutOfMemoryError,并让应用措施终止。那为什么 GC 在此时不能多网络一些工具呢?这就和本日说的引用范例有关了。
起首,从 JDK1.2 开始,工具的引用被分别为4种级别,从而使措施能越发机动地节制工具的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
强引用
强引用(Strong Reference)是行使最广泛的引用。假如一个工具具有强引用,那么它永久不会被 GC。譬喻:
- Object strongReference = new Object();
当内存空间不敷时,JVM 甘愿抛出OutOfMemoryError,使措施非常终止,也不会靠随意接纳具有强引用的工具来办理内存不敷的题目。
假如强引用工具不行使时,必要弱化从而可以被 GC,譬喻ArrayList中的clear()要领:
- /**
- * Removes all of the elements from this list. The list will
- * be empty after this call returns.
- */
- public void clear() {
- modCount++;
-
- // clear to let GC do its work
- for (int i = 0; i < size; i++)
- elementData[i] = null;
-
- size = 0;
- }
显式地配置强引用工具为null,或让其超出工具的生命周期范畴,则垃圾接纳器以为该工具不存在引用,就会接纳这个工具。详细什么时辰网络这要取决于详细的垃圾接纳器。
软引用
假如一个工具只具有软引用(Soft Reference),当内存空间富裕时,垃圾接纳器就不会接纳它;假如内存空间不敷了,就会接纳这些工具的内存。只要垃圾接纳器没有接纳它,该工具就可以被措施行使。让我们来看一个例子详细相识一下:
- String str = new String("abc");
- SoftReference<String> softReference = new SoftReference<>(str);
- String result = softReference.get();
让我们来看一下get():
- public T get() {
- T o = super.get();
- // timestamp代表上一次软引用上一次被行使的时刻(初始化、get())
- // clock代表上一次GC的时刻
- if (o != null && this.timestamp != clock)
- this.timestamp = clock;
- return o;
- }
因此,软引用在被垃圾接纳时,也遵循LRU法例,优先接纳最近起码被行使的工具举办接纳。
软引用的行使场景多是内存敏感的高速缓存。详细来说,就是我们但愿将数据存放到缓存中,这样可以快速举办读取。可是,当 JVM 中内存不足用时,我们又不但愿缓存数据会占用到 JVM 的内存。譬喻共同ReferenceQueue,假如软引用所引用工具被垃圾接纳,JVM 就会把这个软引用插手到与之关联的引用行列中:
- ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
- String str = new String("abc");
- SoftReference<String> softReference = new SoftReference<>(str, referenceQueue);
-
- str = null;
- // Notify GC
- System.gc();
-
- System.out.println(softReference.get()); // abc
-
- Reference<? extends String> reference = referenceQueue.poll();
- System.out.println(reference); //null
可是必要留意的是,假如行使软引用缓存,有也许导致Full GC增多。
弱引用
假如一个工具只具有弱引用(Weak Reference),其生命周期对比于软引用越发短暂。在垃圾接纳器线程扫描它所统领的内存地区的进程中,一旦发明白只具有弱引用的工具,不管当前内存空间足够与否,城市对它举办接纳。不外,因为垃圾接纳器是一个优先级很低的线程,因此不必然会很快发明那些只具有弱引用的工具。其行使为:
- String str = new String("abc");
- WeakReference<String> weakReference = new WeakReference<>(str);
- str = weakReference.get();
讲到弱引用,就不得不提到WeakHashMap。和HashMap对比,当我们给 JVM 分派的内存不敷的时辰,HashMap 情愿抛出 OutOfMemoryError 非常,也不会接纳其响应的没有被引用的工具,而 WeakHashMap 则会接纳存储在个中但有被引用的工具。
WeakHashMap 通过将一些没有被引用的键的值赋值为 null ,这样的话就会奉告GC去接纳这些存储的值了。若是我们专程传入 key 为 null 的键,WeakHashMap 会将键配置为非凡的 Oject,源码为:
- public V put(K key, V value) {
- // key会被从头赋值
- Object k = maskNull(key);
- int h = hash(k);
- Entry<K,V>[] tab = getTable();
- int i = indexFor(h, tab.length);
-
- for (Entry<K,V> e = tab[i]; e != null; ee = e.next) {
- if (h == e.hash && eq(k, e.get())) {
- V oldValue = e.value;
- if (value != oldValue)
- e.value = value;
- return oldValue;
- }
- }
-
- modCount++;
- Entry<K,V> e = tab[i];
- tab[i] = new Entry<>(k, value, queue, h, e);
- if (++size >= threshold)
- resize(tab.length * 2);
- return null;
- }
-
- /**
- * Value representing null keys inside tables.
- * 非凡的key
- */
- private static final Object NULL_KEY = new Object();
-
- /**
- * Use NULL_KEY for key if it is null.
- */
- private static Object maskNull(Object key) {
- return (key == null) ? NULL_KEY : key;
- }
虚引用
虚引用(PhantomReference),顾名思义,就是形同虚设。与其他几种引用都差异,虚引用并不会抉择工具的生命周期。假如一个工具仅持有虚引用,那么它就和没有任何引用一样,在任何时辰都也许被垃圾接纳器接纳。
虚引用首要用来跟踪工具被垃圾接纳器接纳的勾当。 虚引用与软引用和弱引用的一个区别在于:
(编辑:河北网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|