运行时数据区
文章目录
运行时数据区
运行时数据区内有哪些东西
1.8以前: 线程共享的有堆和方法区(永久代是其实现方式) 线程独立的有本地方法栈、虚拟方法栈和程序计数器
1.8以后 线程共享的有堆 线程独立的有本地方法栈、虚拟方法栈和程序计数器 方法区的实现方法变为元空间放在内存中
程序计数器有什么用?生命周期说一下
通过改变程序计数器可以依次读取执行指令,从而实现代码的流控制 另外,每个线程都有一个独立的程序计数器,互不影响。
随着线程的创建而创建,线程消失而消失
虚拟机栈有什么用?是如何运作的?
虚拟机栈内是栈帧。 每调用一次函数,对应的栈帧就会被压入虚拟机栈。里面保存了局部变量表,操作数栈、动态链接、方法出口等信息。
堆内是存什么的
对象实例和数组
所有的对象实例都分配在堆上吗
不是。jdk1.7开始有逃逸分析,如果对象引用没有被返回或者未被外面使用,那么对象可以直接分配在栈上
堆内存是如何分布的
年轻代、老年代和永久代(也就是方法区) 其中,年轻代的Eden survivor0 survivor1的比例是8:1:1 年轻代和老年代的比例是1:2
年轻代什么时候会变成老年代?
每经过一次垃圾回收,年龄+1(从Eden到s区,年龄初始化为1)。年龄到15就会被晋升到老年代。 有别的情况: 会把年轻代中的所有按年龄排序,如果某个年龄的大小超过了s区的一半时,就取这个年龄和15的最小值作为晋升年龄
方法区存储了哪些信息
加载的类的信息,常量,静态变量
为什么要将永久代替换为元空间
因为永久代设置空间大小是很难确定的。空间小容易FullGC和OOM,分配大了就会浪费 而元空间是用本地空间
说一说运行时常量池的变化
1.7以前,运行时常量吃包含字符串常量 1.7 字符串常量池被移到了堆中 1.8 运行时常量池还在方法区中,只不过变成了元空间,到内存中去了
讲一下java对象创建的过程
-
类加载检查 检查能否在常量池中定位到这个类的符号引用,检查是否被加载、验证、准备、解析和初始化
-
内存分配 为新生对象分配内存,可以使用 指针碰撞 或 空闲列表法,取决于堆是否规整
-
初始化零值 将分配到的内存空间初始化为0值
-
设置对象头 设置一些信息在对象头中,比如属于哪个类,年龄等
-
执行init方法 按照程序员的意愿进行初始化
虚拟机对对象初始化时,如何保证线程安全
采用两种方式:
- CAS+失败重试
- TLAB,每个线程私有的缓存空间,如果能存的下就存,存不下在放到堆中。TLAB也在堆中。
对象的内存分布是怎么样的
对象头、实例数据和对齐填充
虚拟机中对象是如何访问定位的
栈上的reference数据来操作堆上的具体对象 有两种方法:使用句柄和直接指针
-
句柄:reference指向句柄,句柄中存着到对象实例的地址和到对象类型的地址
-
直接指针:reference直接指向对象实例数据,然后实例数据有指针指向对象类型数据
哪些包装类在常量池中有缓存数据,缓存数值是多少
Byte[-128,127] Short[-128,127] Integer[-128,127] Long[-128,127] Character[0,127] Boolean直接返回True or False
Integer i1 =33; Integer i2 = 33; i1==i2的结果是什么
Integer i3 = new Integer(33); i3==i2的结果是什么
true,因为能缓存到常量池中
false,因为new Integer是创建对象
讲一下JVM中两种内存分配的方法
指针碰撞: 内存规整的情况下使用,用一个指针表明左边是用过的,右边是没用过的
空闲列表: 堆内存不规整的时候用,用列表记录哪些内存可用
注意: 在操作系统中,是用位图或者链表法。
文章作者 LYR
上次更新 2021-08-17