本文已参与「新人创作礼」活动,一起开启掘金创作之路。
计算机当前矛盾及设计
- CPU和内存及磁盘的读写速率矛盾,引入高速缓冲区
- 多核超线程工艺带来的一致性,使用硬件一致性协议解决
- 主存共享,缓冲区核心独享的数据存储划分
常量池
分类及定义
种类 | 存放内容 | 备注 |
---|---|---|
静态常量池 | 1.静态常量池是类文件描述的一部分 2.有字面量和符号引用组成,类加载完成之后会加载到运行时常量池 | 字面量:文本、字符串、final修饰的内容 符号引用:类、接口、方法、字段的描述信息 |
运行时常量池 | 静态常量池被加载到内存之后,就变成了运行时常量池 | |
字符串常量池 | 由于字符串是最常用的类型,为了性能,单独开辟了一个空间存放字符串 | 1.6及之前存放永久代方法区 1.7之后,字符串常量池存放进堆 |
高频面试
- String str = "aa";最多创建多少个对象。
最多创建一个对象。"aa"是一个字面量,会首先通过
.equals
去字符串常量池查找,如果没有找到,则在堆中创建"aa"的对象,并把该对象的引用维护到字符串常量池中,再返回该引用;如果找到了该对象,直接返回引用。
- String str = new String("aa");最多创建多少个对象。
最多创建两个,new String(),在堆中创建一个String对象,并且如"aa"被认为字面量,最多产生1个对象
- intern()
String s1 = new String("aa");
String s2 = s1.intern();
System.out.println(s1);//aa
System.out.println(s2);//aa
System.out.println(s1.equals(s2));//true
System.out.println(s1==s2);//false
复制代码
intern()返回字符串的规范格式,并且保证字符串是来自同一字符串常量池。如果字符串已经存在,则用equals确定对象,如果字符串不存在,则创建字符串对象,并且返回引用。
String s1 = "aa";
String s2 = s1.intern();
System.out.println(s1);//aa
System.out.println(s2);//aa
System.out.println(s1.equals(s2));//true
System.out.println(s1==s2);//true
复制代码
常量池的内存布局
- 直接内存:越过内核直接访问的内存
- 方法区:
- 类比于计算机主存,线程共享,虚拟机启动时创建,跟进程绑定,存放类结构信息,会OOM
- 方法区是JVM的逻辑概念划分,每个版本的具体实现不一致,在JDK 8中就是Metaspace,在JDK6或7中是Perm Space
运行时数据区划分
运行时数据区 | 创建时机 | 共享范围 | 存储内容 | 内存限制 | 垃圾回收 | 异常错误 |
---|---|---|---|---|---|---|
方法区 | 随虚拟机启动创建 | 同进程绑定,线程共享 | 类的结构信息 各种方法代码 即时编译之后的代码 | 可伸缩调节,有大小参数配置 | 不可以被垃圾回收器管理 | OOM |
堆 | 随虚拟机启动创建 | 同进程绑定,线程共享 | 存储所有的类实例和已分配的数组 | 可伸缩调节,有大小参数配置 | 被垃圾回收器管理,永远不能显式回收 | OOM |
Java虚拟机栈 | 线程创建的时候创建 | 同线程绑定,线程独享 | 存储这栈帧 frames (§2.6). 虚拟机栈只push和pop,栈帧由堆分配 | 可伸缩调节,有大小参数配置 | 被GC管理 | OOM StackOverflowError |
程序计数器 | 线程创建的时候创建 | 同线程绑定,线程独享 | 线程同一时间只能执行一个方法 如果非native方法,则存储虚拟机指令地址 如果native方法则值未定义 存储returnAddress或者本地方法的指针 | 随着线程管理 | ||
本地方法栈 | 不依赖本地方法的线程不创建,依赖的随线程创建而创建 | 线程独享 | 用来调用native方法 | 可伸缩调节,有大小参数配置 | 被GC管理 | OOM StackOverflowError |
栈帧
- 程序计数器是栈帧的一个变量,一个栈帧是一个invoke,一个方法。
- A frame is used to store data and partial results, as well as to perform dynamic linking, return values for methods, and dispatch exceptions.
- 方法调用是创建,调用完成销毁
- 栈帧独有一个本地变量表,操作数栈,指向当前类方法的运行时常量池的引用
栈帧内容 | 作用 | 备注 |
---|---|---|
局部变量表 | 方法中定义的局部变量以及方法的参数 变量不能直接使用,只能通过指令加载进操作数栈,作为操作数使用 类方法(静态方法)索引的位置实际的操作位置就是方法指令,成员方法0位置是this | |
操作数栈 | 压栈和出栈的方式存储操作数 | |
动态链接 | 将符号方法引用转换成具体的方法引用 解析阶段也做过符号引用转直接引用,方法在解析阶段无法确定加载的层级,深度,所以只能在运行时解析,无法在静态解析的时候解析 | |
栈、方法区、堆的互相指向
指向 | 举例 | 备注 |
---|---|---|
栈堆 | 栈帧中变量指向对象 方法中 Object o = new Object(); | |
方法区堆 | private static Object obj=new Object(); | |
堆方法区 | 类的信息存储在方法区中,堆如果需要创建类的话,需要指向方法区 |