场景:

  昨天有位朋友去面试,我问他面试问了哪些问题,其中问了Integer相关的问题,以下就是面试官问的问题,还有一些是我对此做了扩展。

问:两个new Integer 128相等吗?

答:不。因为Integer缓存池默认是-127-128;

问:可以修改Integer缓存池范围吗?如何修改?

答:可以。使用-Djava.lang.Integer.IntegerCache.high=300设置Integer缓存池大小

问:Integer缓存机制使用了哪种设计模式?

答:亨元模式;

问:Integer是如何获取你设置的缓存池大小?

答:sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");

问:sun.misc.VM.getSavedPropertySystem.getProperty有啥区别?

答:唯一的区别是,System.getProperty只能获取非内部的配置信息;例如java.lang.Integer.IntegerCache.highsun.zip.disableMemoryMappingsun.java.launcher.diagsun.cds.enableSharedLookupCache等不能获取,这些只能使用sun.misc.VM.getSavedProperty获取

Integer初始化源码分析:

private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[]; static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h; cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
} private IntegerCache() {}
}

VM.class源码分析:

初始化:

static {
allowArraySyntax = defaultAllowArraySyntax;
savedProps = new Properties();
finalRefCount = 0;
peakFinalRefCount = 0;
initialize();
}

getSavedProperty方法:

public static String getSavedProperty(String var0) {
if (savedProps.isEmpty()) {
throw new IllegalStateException("Should be non-empty if initialized");
} else {
return savedProps.getProperty(var0);
}

savedProps.getProperty方法:

public String getProperty(String key) {
Object oval = super.get(key);
String sval = (oval instanceof String) ? (String)oval : null;
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}

System.java源码分析:

/**
* 初始化系统类。 线程初始化后调用。
*/
private static void initializeSystemClass() { /**
* VM可能会调用JNU_NewStringPlatform()来在“props”初始化期间设置那些编码敏感属性(user.home,user.name,boot.class.path等),
* 它们可能需要通过System.getProperty()进行访问, 在初始化的早期阶段已经初始化(放入“props”)的相关系统编码属性。
* 因此,请确保初始化时可以使用“props”,并直接将所有系统属性放入其中。
*/
props = new Properties();
initProperties(props); // initialized by the VM /**
* 某些系统配置可以由VM选项控制,例如用于支持自动装箱的对象标识语义的最大直接内存量和整数高速缓存大小。 通常,库将获得这些值
* 来自VM设置的属性。 如果属性是
* 仅限内部实现使用,应从系统属性中删除这些属性。
*
* 请参阅java.lang.Integer.IntegerCache和
* 例如,sun.misc.VM.saveAndRemoveProperties方法。
*
* 保存系统属性对象的私有副本,该副本只能由内部实现访问。 去掉
* 某些不适合公共访问的系统属性。
*/
sun.misc.VM.saveAndRemoveProperties(props); lineSeparator = props.getProperty("line.separator");
sun.misc.Version.init(); FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
setIn0(new BufferedInputStream(fdIn));
setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding"))); /**
* 现在加载zip库,以防止java.util.zip.ZipFile稍后尝试使用它来加载此库。
*/
loadLibrary("zip"); // 为HUP,TERM和INT(如果可用)设置Java信号处理程序。
Terminator.setup(); /**
* 初始化需要为类库设置的任何错误的操作系统设置。
* 目前,除了在使用java.io类之前设置了进程范围错误模式的Windows之外,这在任何地方都是无操作的。
*/
sun.misc.VM.initializeOSEnvironment(); /**
* 主线程没有像其他线程一样添加到其线程组中; 我们必须在这里自己做。
*/
Thread current = Thread.currentThread();
current.getThreadGroup().add(current); // 注册共享秘密
setJavaLangAccess(); /**
* 在初始化期间调用的子系统可以调用sun.misc.VM.isBooted(),以避免执行应该等到应用程序类加载器设置完毕的事情。
* 重要信息:确保这仍然是最后一次初始化操作!
*/
sun.misc.VM.booted();
}

重点看这句:sun.misc.VM.saveAndRemoveProperties(props);他会移除系统内部使用的配置,咱们来看看源码是如何操作的。

sun.misc.VM.saveAndRemoveProperties方法:

public static void saveAndRemoveProperties(Properties var0) {
if (booted) {
throw new IllegalStateException("System initialization has completed");
} else {
savedProps.putAll(var0);
String var1 = (String)var0.remove("sun.nio.MaxDirectMemorySize");
if (var1 != null) {
if (var1.equals("-1")) {
directMemory = Runtime.getRuntime().maxMemory();
} else {
long var2 = Long.parseLong(var1);
if (var2 > -1L) {
directMemory = var2;
}
}
} var1 = (String)var0.remove("sun.nio.PageAlignDirectMemory");
if ("true".equals(var1)) {
pageAlignDirectMemory = true;
} var1 = var0.getProperty("sun.lang.ClassLoader.allowArraySyntax");
allowArraySyntax = var1 == null ? defaultAllowArraySyntax : Boolean.parseBoolean(var1);
//移除内部使用的配置,不应该让看到这些配置信息
var0.remove("java.lang.Integer.IntegerCache.high");
var0.remove("sun.zip.disableMemoryMapping");
var0.remove("sun.java.launcher.diag");
var0.remove("sun.cds.enableSharedLookupCache");
}
}

最新文章

  1. c#动态加载卸载DLL的方法
  2. ios 证书申请和发布流程
  3. 【转载】DOS 系统和 Windows 系统有什么关系?为什么windows系统下可以执行dos命令?
  4. SQLServer学习笔记系列5
  5. ecshop show_message
  6. java路径问题总结
  7. oracle闪回表详解
  8. 非洲儿童(南阳oj1036)(馋)
  9. C#推送RTMP到SRS通过VLC进行取流播放!!
  10. (转)java 多线程 CountDownLatch用法
  11. PowerDesigner连接MySQL和逆向工程图
  12. 使用maxwell实时同步mysql数据到kafka
  13. Hbase数据结构模型
  14. 网址,域名,IP,主机名的区别
  15. Brup Suite 渗透测试笔记(八)
  16. 第一章javascript词法结构笔记摘要
  17. [日常] nginx反代websocket
  18. 【平台中间件】Nginx安装配置,实现版本更新不影响服务访问
  19. 将EasyRTMP_RTSP移植到Android平台实现的RTSP拉流转推RTMP直播流功能
  20. NOIP提高组题目归类+题解摘要(2008-2017)

热门文章

  1. element ui表格常用功能如:导出 新增 删除 多选 跨页多选 固定表头 多级表头 合并行列 等常见需求
  2. Kubernetes集群
  3. 处理html换行问题
  4. 手撕面试官系列(十):面试必备之常问Dubbo29题+MySQL55题
  5. linux安装 uwsgi 测试 test.py 不显示hello world 的解决办法
  6. 【论文排版工具】——LaTeX的安装及使用(MiKTeX+TexStudio+Windows)
  7. 如何获取图片上传OSS后的缩略图 超简单
  8. HTML页面导出PDF——高清版
  9. streamController
  10. Mac android studio真机调试步骤