JVM篇

JVM

内存模型

JVM中堆和栈有什么区别?

1.用途:栈存方法;堆存实体对象。

2.生命周期:栈中方法的局部变量会随方法调用结束消失;堆中对象声明周期不确定,在垃圾回收机制确认没用了才回收。

3.存取速度:栈快;堆慢。

4.存储空间:栈小,操作系统管理;堆大,JVM管理。

5.可见性:栈私有,每个线程都有栈;堆共享,任何线程都能访问。

栈中存的是指针?

栈存的是对象的引用,也可以用指针说明,在调用方法时,会指向堆中的对象实例,操作堆的对象实例。

堆分类

image-20250810203120406

如果有个大对象一般是在哪个区域?

大对象通常会直接分配到老年代。

程序计数器的作用,为什么是私有的?

因为CPU的机制,CPU会给每个线程分发时间片。当线程1的时间结束时,即便未完成完所有任务,会切换到线程2,执行到线程2的时间结束,再从线程1未完成的部分开始。

程序计数器用来记录当前线程所执行的字节码的行号指示器

方法区中的方法的执行过程?

解析方法调用,栈帧创建,执行方法,返回处理。

String保存在哪里?

字符串常量池。它的值不可变,可以被多个引用。

String s = new String(“abc”)执行过程中分别对应哪些内存区域?

如果初次创建,则创建两个对象,一个在字符串常量池,一个在堆。如果字符串常量池已经有,则只会创建堆中一个对象。

引用类型有哪些?有什么区别?

分为强软弱虚:

  • 强引用,普遍的赋值关系,如A a = new A(),永远不会被GC(Garbage Collection)
  • 软引用,SoftReference。系统在发生内存溢出前会对这类对象回收。
  • 弱引用,WeakReference。弱引用的对象下一次GC一定会回收。
  • 虚引用,同样的当发生GC的时候,虚引用也会被回收。用来管理堆外对象。

弱引用了解吗?举例说明在哪里可以用?

在java中,弱引用通过WeakReference类实现。弱引用的一个主要用途是创建非强制性对象引用,当内存压力过大时被垃圾回收清理,从而避免内存泄漏。

使用场景:

  • 缓存系统:JVM在系统内存压力大时,清理弱引用对象。
  • 对象池:在对象池中,弱引用用来管理暂时不用的对象。
  • 避免内存泄漏:当一个对象不应该被长期引用时,使用弱引用可以防止该对象被意外地保留,从而避免潜在的内存泄露。

内存泄漏和内存溢出

内存泄漏:程序在运行中,存在不再使用的对象仍然被引用,无法被垃圾回收,导致内存被不断占用。

内存泄漏常见原因:

  • 静态集合:使用静态数据结构(如HashMap等存储结构)未及时清理。
  • 事件监听:未及时取消对事件的监听,导致该事件持续被引用。
  • 线程:未停止的线程可能持有对象引用,无法被回收。

内存溢出:OutOfMemoryError,JVM在申请内存的时候,无法找到足够的内存。

内存溢出常见原因:

  • 大量对象创建:程序不断创建对象,超出JVM堆的限制。
  • 持久引用:大型数据结构长时间持有引用,占据大量内存。
  • 递归调用:深度递归导致栈溢出。

JVM内存结构的几种溢出情况

  • 堆溢出:大对象分配时,没有足够空间。

  • 栈溢出:深度递归导致。

  • 元空间溢出:系统的代码非常多,引用的第三方包非常多,通过动态代码生成类加载等方法

  • 直接内存溢出:在使用ByteBuffer中的allocateDirect()的时候会用到,很多JavaNIO(像netty)的框架中被封装为其他的方法,出现该问题时会抛出Java.lang.OutOfMemoryError: Direct buffer memory异常。

内存泄漏和内存溢出的例子

  • 静态属性导致内存溢出:用static创建修饰的对象太多,static修饰的变量会直到应用结束才回收。

  • 未关闭的资源:数据库链接,输入流和session对象。

  • 使用ThreadLocal:线程ThreadLocal的实现中,每个线程都维护一个ThreadLocalMap映射表。当设置set ThreadLocalMap中就会出现key为null的Entry。如果当前线程不结束,改引用就不会被回收,导致内存泄露。

    ​ 解决方法:1.使用remove彻底清除;2.不适用set(null),因为为空还是存在。3.在final中写结束线程。

类初始化和类加载

创建对象过程

类加载检查——分配内存——初始化零值——对象头——构造函数Init

类加载器有哪些?

启动类加载器——拓展类加载器——系统类加载器/应用类加载器——自定义类加载器

双亲委派模型

双亲委派模型:当某一加载器收到类加载请求,就会从上一级类加载器中寻找,每级都是如此。

如果没有再返回下一级。

作用:

  • 保证类的唯一性。
  • 保证安全性。
  • 支持隔离和层次划分。
  • 简化了加载流程。

类加载流程

七个阶段:加载——验证——准备——解析——初始化——使用——卸载
主要分为:加载——连接——初始化

加载:变为.class.jar这类

垃圾回收

什么是垃圾回收?如何触发?

垃圾回收是自动释放不再被程序引用的对象所占用的内存。

触发:

  • 内存不足时。
  • 手动请求。
  • JVM参数。
  • 对象数量或内存达到JVM阈值。

判断垃圾回收的方法

1.引用计数法

2.可达性分析算法:从GC Root出发,当引用对象和GC Root没有连接,就代表该引用对象是没被引用的。就可出发垃圾回收。

垃圾回收算法有哪些?

  • 标记清除
  • 标记整理
  • 复制算法
  • 分代回收算法

minorGC、majorGC、fullGC的区别,什么场景触发full GC

MinorGC:新生代触发,将存活对象移入老生代。

MajorGC:主要针对老年代触发,清理老年代。

FullGC:清理所有堆内存,会触发stop the world.

​ 触发条件:1.直接调用命令。2.MinorGC存活对象无法全部放到老年代出发。3.JDK8以前永久代空间不足,JDK8以后,元空间空间不足。

垃圾回收器有哪些?

image-20250814115935193

CMS和G1的区别

区别一:使用范围不一样:

  • CMS是在老年代,可以配和新生代收集器使用。
  • G1收集范围是老年代和新生代。

区别二:STW的时间:

  • CMS以最小停顿时间为目标
  • G1可预测垃圾回收停顿时间

区别三:垃圾碎片:

  • CMS使用“标记-清理”算法,容易产生内存碎片
  • G1使用“标记-整理”算法,不产生内存碎片

使用场景:

CMS使用场景:

  • 低延迟需求:
  • 老年代收集:
  • 碎片化管理:

G1使用场景:

  • 大堆内存
  • 对内存碎片敏感
  • 比较平衡的性能

GC会对哪些内存垃圾回收

1.堆。

2.方法区。


JVM篇
http://example.com/2025/08/10/JVM篇/
作者
Luogic
发布于
2025年8月10日
许可协议