JVM实例和main()方法

当A和B两个类继承C,A的main方法阻塞,B的main方法执行时,为何C类加载两次?实际上,每个main方法对应一个独立的JVM实例,因此在每个JVM中,C类只会被加载一次。

别人问了我一个问题
假设A和B都继承C
A的main方法执行 阻塞
B的main方法执行
为什么C加载了两次?

答案:一个main方法对应一个JVM实例 因此在每个JVM中C只加载了一次

-------------------------------------------------------

记住:每一个Java应用都唯一对应一个JVM实例,每一个JVM实例唯一对应一个堆。

Java虚拟机(JVM)的内存模型中,方法堆是两个重要的内存区域,它们在内存分配、管理以及用途上有着明确的区分与联系。 ### 方法区的作用与特点 方法区在JVM中主要用于存储类的元数据信息,包括类的结构信息(如类名、访问修饰符、字段、方法等)、常量池、静态变量以及编译器编译后的代码。根据《Java虚拟机规范》,方法区在逻辑上属于堆的一部分,但它通常被称为“非堆”,以区别于Java堆中用于存储对象实例的区域。这种设计的目的是为了强调方法区与堆的其他部分在功能上的差异[^1]。 在早期的JVM实现中,方法区通常与堆共享同一块内存区域,但随着JVM的发展,特别是在JDK 1.8中,方法区的实现被元空间(Metaspace)所取代,元空间从堆内存中独立出来,使用本地内存(Native Memory)进行存储。这一变化旨在解决方法区大小受限于堆内存的问题,并减少因类元数据过多而导致的内存溢出风险。 ### 堆的作用与特点 堆是JVM中用于存储对象实例的主要内存区域。所有通过`new`关键字创建的对象都会在堆上分配内存空间。堆被划分为不同的代(Generation),主要包括新生代(Young Generation)老年代(Old Generation),以便于垃圾回收器更高效地管理内存[^3]。 ### 方法区与堆的交互 尽管方法区在逻辑上被认为是堆的一部分,但实际上,它们在功能管理上是相对独立的。方法区主要负责存储类的元数据,而堆则专注于对象实例的存储。在类加载过程中,类的元数据会被加载到方法区,而类的实例对象则会被分配到堆中。例如,当一个类被加载时,其结构信息会被存储在方法区,而该类的对象实例则会在堆中创建,并通过方法区中的类信息来初始化[^2]。 此外,JVM还支持一种优化技术——栈上分配(Stack Allocation),即如果一个对象的引用不会超出当前方法的作用域,那么JVM可以选择将这个对象分配到栈上,而不是堆上。这种方法可以减少堆内存的压力,并避免垃圾回收带来的性能开销。例如,在以下代码中,`Point`对象的引用仅限于`createObject()`方法内部,因此可以被分配在栈上: ```java public class StackAllocationExample { public static void main(String[] args) { for (int i = 0; i < 1000000; i++) { createObject(); } } public static void createObject() { // 这里创建的对象未发生逃逸 Point point = new Point(1, 2); } } class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } } ``` ### 方法区与堆的调用关系 当程序开始运行时,如`main`方法被调用,JVM会创建一个新的线程,并在该线程的虚拟机栈中创建一个栈帧,用于存储`main`方法的局部变量操作数栈。如果在`main`方法中创建了一个对象,如`MyObject obj = new MyObject();`,JVM会在堆上为这个对象分配内存,并在当前栈帧的局部变量表中存储这个对象的引用。如果`main`方法调用了另一个方法,如`obj.someMethod()`,JVM会在虚拟机栈中为`someMethod`创建一个新的栈帧,并将其压入栈顶。当`someMethod`执行完毕,它的栈帧会从虚拟机栈中弹出,控制权返回到`main`方法的栈帧。当`main`方法执行结束,JVM会结束该线程,此时该线程的虚拟机栈会被销毁。垃圾回收器会定期检查堆中的对象,回收那些不再被任何栈帧引用的对象,以释放内存空间[^3]。 ### 总结 综上所述,方法堆在JVM中各自承担着不同的职责。方法区主要用于存储类的元数据,而堆则用于存储对象实例。虽然方法区在逻辑上属于堆的一部分,但它们在实现上通常是独立的。随着JVM的发展,方法区的实现也在不断演进,最终在JDK 1.8中被元空间所取代,进一步优化了内存管理[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

添码星空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值