源码随想 String -> SoftReference
源码随想 String -> SoftReference
2021年7月27日 15:38:14
今天实习时看 String的源码,发现其中的一个构造方法
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException {
if (charsetName == null)
throw new NullPointerException("charsetName");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charsetName, bytes, offset, length);
}
在 StringCoding.decode()方法处点入之后,发现其实现如下:
static char[] decode(String charsetName, byte[] ba, int off, int len)
throws UnsupportedEncodingException
{
StringDecoder sd = deref(decoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((sd == null) || !(csn.equals(sd.requestedCharsetName())
|| csn.equals(sd.charsetName()))) {
sd = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null)
sd = new StringDecoder(cs, csn);
} catch (IllegalCharsetNameException x) {}
if (sd == null)
throw new UnsupportedEncodingException(csn);
set(decoder, sd);
}
return sd.decode(ba, off, len);
}
在 deref()方法处点入,发现其实现如下:
private static <t> T deref(ThreadLocal<softreference<t>> tl) {
SoftReference<t> sr = tl.get();
if (sr == null)
return null;
return sr.get();
}
没想到,这个 decoder居然是一个存放在 ThreadLocal里的 软引用!!!
关于 tl.get(),也就是 ThreadLocal :: get(),虽然还没看过这部分代码,但是在马士兵的课上和一些面经上面都强调过它的重要性,在这里一看到,忽然有一种他乡遇故知的感受。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
不止如此,在 sr.get()方法中,有两个很奇怪的量 clock和 timestamp
public T get() {
T o = super.get();
if (o != null && this.timestamp != clock)
this.timestamp = clock;
return o;
}
进入到 SoftReference.java类中之后,有如下定义:
/**
* Timestamp clock, updated by the garbage collector
*/
static private long clock;
/**
* Timestamp updated by each invocation of the get method. The VM may use
* this field when selecting soft references to be cleared, but it is not
* required to do so.
*/
private long timestamp;
也就是说,clock会在每次进行垃圾收集的时候更新;timestamp会在每次方法调用的时候更新。JVM通过对 timestamp字段的监测来判断是否需要清楚弱引用。
那么到底什么时候真正进行软引用的清理呢?
首先,软引用中有一个全局变量 clock,在每一次垃圾回收的时候,它的值都会更新(in millis)。
同时,每一个软引用都有一个 timestamp变量,当前软引用每次被访问的时候都会更新(包括 初始化 和 调用get()方法)
当一次新的垃圾回收开始时,是否要回收一个软饮用对象依据如下:
timestamp的年龄多大了- 剩下的堆空间还有多少
具体的计算方式如下:
free_heap为堆中的空余空间大小(以 MB为单位)interval是上一次 GC和 现在timestamp的时间差,ms_per_mb是一个常量,保持堆中空余的每MB空间中的 软引用 的毫秒值
interval <= free_heap * ms_per_mb
举个例子:
如果当前的某个软引用 A,它的 timestamp值为 2000ms,上一次 GC的 clock时间是 5000ms,ms_per_mb常量的大小是 1000,空闲的堆空间为 1MB,那么,计算可得
5000 - 2000 <= 1 * 1000 是假的,返回 false
所以我们需要清理掉这个软引用。
那么如果假设堆空间比较大,比如是 4MB,那么计算可得
5000 - 2000 <= 4 * 1000 是真的
所以我们不需要清理这个软引用
需要注意到的是:
一个软引用在一次访问之后,至少会存活一次 GC。
因为:
interval的值是我们通过 clock和 timestamp计算出来的,而 clock是上一次的 FGC时间,既然有上一次的 GC,说明它肯定至少得活过一次 GC呀。
此外,每当一个引用在某次垃圾回收之后被访问到了,那么 timestamp的值会被设置成和 clock一样,然后 interval就变成了 0,软引用就肯定不会被回收了。
想想也是的呀,针对经常在用的对象,我们肯定是要保留的呀。</softreference
源码随想 String -> SoftReference的更多相关文章
- JDK源码学习--String篇(二) 关于String采用final修饰的思考
JDK源码学习String篇中,有一处错误,String类用final[不能被改变的]修饰,而我却写成静态的,感谢CTO-淼淼的指正. 风一样的码农提出的String为何采用final的设计,阅读JD ...
- 深入源码剖析String,StringBuilder,StringBuffer
[String,StringBuffer,StringBulider] 深入源码剖析String,StringBuilder,StringBuffer [作者:高瑞林] [博客地址]http://ww ...
- JDK源码之String类解析
一 概述 String由final修饰,是不可变类,即String对象也是不可变对象.这意味着当修改一个String对象的内容时,JVM不会改变原来的对象,而是生成一个新的String对象 主要考虑以 ...
- JDK1.8源码学习-String
JDK1.8源码学习-String 目录 一.String简介 String类是Java中最常用的类之一,所有字符串的字面量都是String类的实例,字符串是常量,在定义之后不能被改变. 二.定义 p ...
- JDK源码学习--String篇(四) 终结篇
StringBuilder和StringBuffer 前面讲到String是不可变的,如果需要可变的字符串将如何使用和操作呢?JAVA提供了连个操作可变字符串的类,StringBuilder和Stri ...
- JDK源码学习--String篇(三) 存储篇
在进一步解读String类时,先了解下内存分配和数据存储的. 数据存储 1.寄存器:最快的存储区,位于处理器的内部.由于寄存器的数量有限,所以寄存器是按需分配. 2.堆栈:位于RAM中,但是通过堆栈指 ...
- JDK源码学习--String篇(-)
工作三年了,用了三年的JAVA,突然发现竟然没有好好的看下JDK的源码,整天用着的String,只是大概知道怎么回事,其中的实现逻辑却是一头雾水. 知耻而后勇,加油!!! java.lang.Stri ...
- java基础进阶一:String源码和String常量池
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/8046564.html 邮箱:moyi@moyib ...
- [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析
String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识, ...
随机推荐
- 分享一个WPF 实现 Windows 软件快捷小工具
分享一个WPF 实现 Windows 软件快捷小工具 Windows 软件快捷小工具 作者:WPFDevelopersOrg 原文链接:https://github.com/WPFDevelopers ...
- Bika LIMS 开源LIMS集—— SENAITE的使用(分析/测试、方法)
分析/测试项目分类(Test Category) 定义检测项目的分类,例如理化检测.微生物检测,或者按样品的维度定义,例如食品检测.水质检测等. 分析方法(Test Method) 定义实验室分析方法 ...
- 原型设计工具Axure RP9下载、汉化操作说明(赠授权码)
Axure是产品经理.交互设计常用的一款原型设计工具,能实现比较复杂的交互效果.其实在功能上是十分齐全的,并且其交互的样式也比较多样,主要是通过动态面板.函数.中继器等几个模块就几乎可以实现任何常见的 ...
- Linux 时间设置和同步服务
修改日期时间的工具 date hwclock timedatectl date工具的使用 作用:显示和设置系统时间 选项: -d <字符串> 显示字符串所指的日期与时间,比如:" ...
- BZOJ3894/LuoguP4313 文理分科 (最小割)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> ...
- package.json 与 package-lock.json 的关系
模块化开发在前端越来越流行,使用 node 和 npm 可以很方便的下载管理项目所需的依赖模块.package.json 用来描述项目及项目所依赖的模块信息. 那 package-lock.json ...
- 聊天机器人框架Rasa资源整理
Rasa是一个主流的构建对话机器人的开源框架,它的优点是几乎覆盖了对话系统的所有功能,并且每个模块都有很好的可扩展性.参考文献收集了一些Rasa相关的开源项目和优质文章. 一.Rasa介绍 1.R ...
- 从0到1写一款自动为Markdown标题添加序号的Jetbrains插件
1. markdown-index 最近做了一个Jetbrains的插件,叫markdown-index,它的作用是为Markdown文档的标题自动添加序号,效果如下: 目前已经可以在Jetbrain ...
- SDIO移植
1.拷贝 STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Utilities\STM32_EVAL\STM324x7I_EVAL 目录下的stm324x7i_eval_sdio_ ...
- helm安装kube-state-metrics-4.16.0
Application version 2.5.0 Chart version 4.16.0 获取chart包 helm repo add prometheus-community https://p ...