Java内存区域
常见面试题:
- 介绍下 Java 内存区域(运行时数据区)
- Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么)
- 对象的访问定位的两种方式(句柄和直接指针两种方式)
拓展问题:
- String类和常量池
- 8种基本类型的包装类和常量池
介绍下 Java 内存区域(运行时数据区)?
虚拟机VM栈(为java字节码服务):
局部变量表:8种基本数据类型 +对象引用
两种异常:StackOverFlowError:JVM栈内存大小不允许动态扩展时,线程请求栈超过VM栈最大深度时。
OutOfMemoryError:JVM栈内存大小允许动态扩展,且内存用完而无法动态扩展时(无法申请到内存)。 OOM
本地方法栈:虚拟机栈为Java方法 字节码服务,本地方法栈为Native方法服务。
堆:
JVM启动时,存放 对象实例、数组
Java堆是GC垃圾收集器管理的主要区域
方法区:
class类信息、常量、static静态变量、编译后的代码
运行时常量池:存放编译期生成的各种字面量和符号引用
Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么)?
1)类加载检查:
JVM检查:1. 能否在常量池中定位 类的符号引用? 2.类是否被加载、解析、初始化过?
2)分配内存:
从堆中分配内存;方式有1.指针碰撞 2.空闲列表
内存分配并发问题(线程安全):
1. CAS+失败重试。CAS是乐观锁,遇到失败就不断重试。
2. TLAB。为每个线程预先分配一块内存,当TLAB内存不够用时,再采用CAS方法分配。
3)初始化零值:
将分配的内存全初始化为0(不包括对象头),这样直接可用
4)设置对象头:
对象信息存放在对象头中。1. hashCode、GC分代年龄、锁状态标志 2. 对象指向它的类的指针
5)执行init方法:
按照java程序进行init 初始化
对象的访问定位的两种方式(句柄和直接指针两种方式)?
通过栈上的引用来操作堆上的对象,访问方式由JVM决定:使用句柄 / 直接指针
1)句柄:引用指向句柄,句柄池中存储:对象实例数据 (堆) / 对象类型数据 (方法区)
2)直接指针:引用直接指向 对象实例数据 (堆),然后再从堆指向 对象类型数据 (方法区)
String类和常量池 ?
str1指向常量池已有对象;str2指向堆里新建的对象
str1 != str2 对象内容相同,但不是同一个对象
s1,new String()指向堆中的对象;s3常量池(双引号的都是常量池);s2使用intern在常量池中创建字符串( intern 在常量池中有字符串时直接用,没有时会新建字符串)
== 更严格 .equals 比较松
字符串拼接的情况:
String s1 = new String("abc");这句话创建了几个对象? 2个
8种基本类型的包装类和常量池 ?
除了Float和Double没有实现常量池技术(所以每次都会在堆上新建对象)
其他6种,都实现了常量池技术,默认创建了数值[-128,127]缓存数据(仅在此范围有常量池,超出就没有了)
整理下下面的材料:
java内存分析:对象通过引用来操作的:栈 => 堆(地址)