java虚拟机,2021Java开发社招面试总结

如果正在执行一个Native方法,那么这个计数器值将为空。

虚拟机栈

线程私有,生命周期跟线程相同。

每个方法在执行同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

在Java虚拟机规范中,对这个区域规定了两种异常情况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;

如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

本地方法栈

跟虚拟机栈所发挥的作用相似,区别在于虚拟机栈为虚拟机执行Java(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。

Java堆

用于存放对象实例,是Java虚拟机所管理的内存中最大的一块,同时也是所有线程共享的一块内存区域。

因为Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC"堆。由于现在收集器基本都采用分代收集算法,所以Java堆还可以细分为

新生代

老年代

永久代(永久代是Hotspot虚拟机特有的概念,是方法区的一种实现,别的JVM都没有这个东西。在Java 8中,永久代被彻底移除,取而代之的是另一块与堆不相连的本地内存——元空间。)

当一个对象被创建时,它首先进入新生代,之后有可能被转移到老年代中。

新生代存放着大量的生命很短的对象,因此新生代在三个区域中垃圾回收的频率最高。为了更高效地进行垃圾回收,把新生代继续划分成以下三个空间:

Eden

From Survivor

To Survivor

方法区

与Java堆一样,各个线程共享的内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。

运行时常量池

方法区的一部分,用于存放编译器生成的各种字面量和符号引用。

运行时常量池相对于class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。

直接内存

在JDK1.4中新加入了NIO类,引入了一种基于通道与缓冲区的I/O方法,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

堆外内存之 DirectByteBuffer详解

HotSpot虚拟机对象

对象的创建

在语言层上,创建对象通常仅仅是一个new关键字而已,而当虚拟机遇到一条new执行时,将由一下步骤:

检查类是否加载、解析、初始化过,没有则先执行相应的类加载过程。

在堆中分配内存

划分可用空间:

指针碰撞:堆内存规整

空闲列表:堆内存不规整

并发问题

同步:采用CAS配上失败重试的方式保证更新操作的原子性

把内存分配动作按照线程划分在不同的空间之中进行

将分配到的内存空间都初始化零值

设置对象的类实例、元数据、哈希码、GC分代年龄等信息。

执行方法

对象的内存布局

对象在内存中储存的布局可以分为3块区域:

对象头

对象运行时数据、哈希码、GC分代年龄、锁状态标记、线程持有的锁、偏向线程ID等

类型执行:即对象执向它的类元数据的指针,指明对象数据哪个类的实例。

实例数据

对象真正存储的有效信息

对齐填充

占位符作用

对象的访问定位

句柄定位

直接指针

垃圾收集器

程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收。垃圾回收主要是针对 Java 堆和方法区进行。

判断对象是否死亡

引用计数算法

给对象添加一个引用计数器,每当有一个地方引用它,计数器值就加1;引用时效时,计算器值就减1;当计数器值为0的对象就是不可能再被使用的。

当两个对象相互引用时,此时引用计数器的值永远不为0,导致无法对它们进行垃圾回收。

public class ReferenceCountingGC {

public Object instance = null;

public static void testGC() {

ReferenceCountingGC objA = new ReferenceCountingGC();

ReferenceCountingGC objB = new ReferenceCountingGC();

objA .instance = objB ;

objB .instance = objA ;

objA = null;

objB = null;

System.gc();

}

}

可达性分析算法

以GC Roots为起始点,从这些节点开始向下搜索,能够搜索到的对象都是存活的,不可达的对象则为不可用。

java虚拟机

在Java语言中,可作为GC Roots的对象包括下面几种:

虚拟机栈中引用的对象

方法区中静态属性引用的对象

方法区中常量引用的对象

本地方法栈中Native方法引用的对象

引用类型

无论是引用计数算法还是可达性分析算法判断对象是否存活都与引用有关。在JDK1.2之后,Java对引用的概念进行了扩充,划分为强度不同的四个的引用类型。

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

强引用

通过new来创建对象的引用类型,被强引用的对象永远不会被垃圾收集器回收。

Object obj = new Object();

软引用

通过SortReference类来实现,只有在内存不足的时候才会被回收。

Object obj = new Object();

SoftReference sr = new SoftReference(obj);

obj = null;

弱引用

通过WeakReference类来实现,只能存活到下一次垃圾收集发生之前。

Object obj = new Object();

WeakReference wr = new WeakReference(obj);

obj = null;

WeakHashMap 的 Entry 继承自 WeakReference,主要用来实现缓存。

private static class Entry<K,V> extends WeakReference implements Map.Entry<K,V>

Tomcat 中的 ConcurrentCache 就使用了 WeakHashMap 来实现缓存功能。ConcurrentCache 采取的是分代缓存,经常使用的对象放入 eden 中,而不常用的对象放入 longterm。eden 使用 ConcurrentHashMap 实现,longterm 使用 WeakHashMap,保证了不常使用的对象容易被回收。

public final class ConcurrentCache<K, V> {

private final int size;

private final Map<K, V> eden;

private final Map<K, V> longterm;

public ConcurrentCache(int size) {

使用的对象放入 eden 中,而不常用的对象放入 longterm。eden 使用 ConcurrentHashMap 实现,longterm 使用 WeakHashMap,保证了不常使用的对象容易被回收。

public final class ConcurrentCache<K, V> {

private final int size;

private final Map<K, V> eden;

private final Map<K, V> longterm;

public ConcurrentCache(int size) {

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值