对象创建
New → 常量池定位 → 加载类 → 分配内存(指针碰撞/空闲列表) → 初始化 → init方法
对象内存布局
_对象头(32/64 bit)
|_哈希码、Gc分代年龄、锁状态…,类型指针
_实例数据
_对齐填充
对象访问定位
句柄(稳定),直接指针(快速)
句柄:java堆划分一块内存作为句柄池,reference中存储对象句柄地址,句柄中包含对象实例数据与类型数据各自的具体地址信息,reference → java栈,句柄池,实例池 → java堆,对象数据类型 → 方法区
直接指针:reference存放对象地址,对象地址中包含实例数据和一个指向对象类型的指针
tips:句柄和直接指针的一个显著区别就是句柄方式的reference指向两个指针,直接指针的reference指向一个指针,作者在书中提到直接指针需要考虑如何放置访问类型数据的相关信息但是没做具体介绍,我认为应该是直接指针的方式中对象信息包含对象的实例数据信息和一个类似与头的对象类型指针,具体怎样实现不得而知。
书中给了几段OOM异常示例代码,其中一段代码存疑,贴上来希望有大神看到可以帮帮忙解惑
public class RuntimeConstantPoolOOM{
public static void main(String[] args){
String str1=new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern()==str1);
String str2=new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern()==str2);
System.out.println(System.getProperty("java.version"));
}
}
运行结果
true
false
1.8.0_131
书中的原解释是
JDK 1.7(以及部分其他虚拟
机,例如JRockit)的intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。对str2比较返回false是因为“java”这个字符串在执行StringBuilder.toString()之前已经出现过,字符串常量池中已经有它的引用了,不符合“首次出现”的原则,而“计算机软件”这个字符串则是首次出现的,因此返回true。
本人用的jdk1.8应该没有影响,运行结果也符合作者所言,但是作者提到第二个false是因为前面出现过“java”这个字符串,本人在程序中并没有看到“java”字符串,试过其他字符串“public”和“class”都返回true,而“void”和“main”则返回false,所以想搞清楚作者文中的“前面出现过”的具体含义是什么。
ps:笔记内容大多来自周志明所著《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》