Java面试问题总结——如果老年代对象引用年轻代对象,年轻代对象是否会被垃圾回收?

本文详细介绍了Java内存的五大数据区域,包括程序计数器、虚拟机栈、本地方法栈、方法区和堆,以及直接内存。特别讨论了堆内存的分代模型和垃圾回收机制,包括垃圾收集的判断方法、方法区的垃圾回收以及各种垃圾收集算法。此外,还探讨了老年代对象引用年轻代对象时的垃圾回收情况。
摘要由CSDN通过智能技术生成

目录

一、Java内存管理

1.程序计数器(Program Counter Register)

2.虚拟机栈(Virtual Machine Stack)

3.本地方法栈(Native Method Stack)

4.方法区(Method Area)

5.堆(Heap)

6.直接内存

二、Java垃圾回收机制

1.垃圾回收判断方法

2.方法区的垃圾回收判断

3.垃圾收集算法

4.垃圾收集器

三、如果老年代对象引用年轻代对象,年轻代对象是否会被垃圾回收?


一、Java内存管理

在C语言中,开发人员可以直接访问内存并在代码中引用内存单元,这种机制虽然也有好处但一旦出现问题也很难定位问题。对于Java开发人员来说,则没有这样的烦恼,因为Java直接将内存管理交由JVM来管理,这样开发人员在编写程序的时候就不用担心内存的使用情况而可以专注内容的实现。但这其实也造成了一点隐患,如果不了解JVM内存管理的机制,很可能会因一些错误的代码写法而导致内存泄漏或内存溢出。

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间。JVM管理的内存包含程序计数器、虚拟机栈、本地方法栈、方法区和堆,下面内容根据数据区域详细介绍。

Java内存管理结构图

1.程序计数器(Program Counter Register)

程序计数器是一块较小的内存空间,可以看作当前线程所执行字节码的行号指示器,即指向正在执行的字节码。在概念模型中,字节码解释器的工作就是通过改变这个程序计数器的值来选取下一条字节码的指令,分支、循环、跳转、异常处理、线程恢复等基础功能都要依赖这个计数器来完成。

多线程中,为了让线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间互不影响、独立存储,因此该内存是线程私有的。当线程正在执行的是一个Java方法,这个计数器记录的是在正在执行的虚拟机字节码指令的地址;当执行的是Native方法,这个计数器值为空。

注意:此内存区域是唯一一个没有规定任何 OutOfMemoryError 情况的区域 ,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。

2.虚拟机栈(Virtual Machine Stack)

虚拟机栈是线程私有的内存空间,每个线程都有一个线程栈,每个方法被执行时都会创建一个栈帧,方法执行完成,栈帧弹出,线程运行结束,线程栈被回收。

虚拟机栈就是Java中的方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧,这个栈帧用于存储局部变量表、操作数栈指向当前方法所属的类的运行时常量池的引用、方法返回地址等信息,每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

局部变量表存储了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型(指向了一条字节码指令的地址)。局部变量表的大小在编译器就可以确定其大小,并且在程序执行期间局部变量表的大小是不会改变的。

程序中的所有计算过程都是在借助于操作数栈来完成的。

指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向当前方法所属的类的运行时常量池

方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。

虚拟机栈可能会出现 StackOverFlowError 和 OutOfMemoryError 两种内存异常问题:

  1. StackOverFlowError: 若 Java 虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。
  2. OutOfMemoryError: 若 Java 虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出 OutOfMemoryError 错误。

3.本地方法栈(Native Method Stack)

该内存区域和虚拟机栈所发挥的作用非常相似,主要区别是虚拟机栈为JVM执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中把本地方法栈和 JVM 合二为一。

本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。

方法执行完毕后相应的栈帧也会出栈并释放内存空间,也会出现 StackOverFlowError 和 OutOfMemoryError 两种错误。

4.方法区(Method Area)

方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息(包括类的名称、方法信息、成员变量信息)、常量静态变量、以及编译器编译后的代码等数据。

方法区存放的数据一般不会发生垃圾回收,垃圾回收的主要目标是常量池的回收和类的卸载。当方法区中无法申请到足够的内存时,将会抛出 OutOfMemoryError 异常

运行时常量池(Runtime Constant Pool)是方法区的一部分,Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(存放编译期生成的各种字面量和符号引用)。

  • 字面量:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量
  • 符号引用:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符

注意:JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值