Jvm(13),运行时数据---共享区---jvm方法区

本文详细解析JVM方法区的存储机制,包括其线程安全性、动态调整特性及垃圾回收过程。阐述方法区与常量池的关系,以及类加载过程中的作用。探讨不同JDK版本下方法区的配置差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html

 

方法区就是自己以前理解的常量池,只不过以前理解的比较片面而已,它不是在jvm堆中的,不要被jvm 笔记7所误解。它们是有共同点的就是都是共享的。

一,网上的解释(方法区)

当jvm使用类装载器装在某个类时,它首先要定位到对应的class文件,然后读入这个class 文件,    后提取该文件的内容信息,并将这些信息存储到方法去,    后返回一个class实例。

方法区是系统分配的一个内存逻辑区域,是一块所有线程共享的内存区域,用来存储类型信息(类型信息可以理解为类的描述信息(类的全限定名,访问修饰符,字段,方法等)),方法区的大小决定了系统可以包含多少个类,如果系统类太多,方法区内存不够会导致方法区溢出,虚拟机同样会抛出内存溢出信息。方法去特点:

1.方法区是线程安全的,由于所有的线程都共享方法区,所以方法区里的数据访问必须被设计成线程安全的。例如,假如同时有两个线程都企图访问方法区中的同一个类,而这个类还没有被装入jvm,那么只允许一个线程去装在它,而其他线程必须等待。

2.方法去的大小不必是固定的,jvm可根据应用需要动态调整,同时,方法区也不一定是连续的,方法区可以在一个堆(甚至是jvm自己的堆)中自由分配。

3.方法区也可被垃圾收集,当某个类不在被使用时,jvm将卸载这个类,进行垃圾收集。

方法区存放内容:

1.类的全限定名(类的全路径名)。

2.类的直接超类的权全限定名(如果这个类是Object,则它没有超类)。

3.类的类型(类或接口)。

4.类的访问修饰符,public,abstract,final等。

5.类的直接接口全限定名的有序列表。

6.常量池(字段,方法信息,静态变量,类型引用(class))等类变量:类变量为静态变量,在方法去中有个静态去,静态去专门用来存放静态变量以及静态块。

方法区内存大小设置: jdk1.6,jdk1.7 永久区

-XX:PermSize=10M 初始化方法区大小为10M。

-XX:MaxPermSize 方法区    大内存为10M。

-XX:PrintGCDetails 打印日志详情。

jdk1.8 元数据区

-XX:MetaspaceSize=10M

-XX:MaxMetaspaceSize=10M

元数据区发生溢出,虚拟机一样抛出异常,如下: java.lang.OutOfMemoryError Metaspace

其实这里我们    主要的看得及时方法区中都有什么信息。下面我们来看一下常量池的内容。二,常量池

首先我们来看一下这段代码

         String a="abc";

         String b="abc";          System.out.println(a==b); 结果是true

我们可以看到a和b并不是在堆中创建的,假如在堆中创建a和b就不相等了,所以只能在常量池中创建,常量池里面对比的时候用的是hashset,这个时候,hashset是无序的,这个时候假如a=abc到了常量池中,b再进来的时候发现同样是abc就不会创建,还是原来的abc 的值。所以是true。

         String a="abc";

         String b=new String("abc");

         System.out.println(a==b);

结果是false

这个时候的b就会在堆中创建对象,而a在常量池中肯定是不相等的。

         String a="abc";

         String b=new String("abc");

         System.out.println(a==b.intern()); 这个时候就结果就是true了。这有事为什么呢。

这个时候就相当于把b从堆中移到常量池中去了。这个常量就叫做运行时常量。、

其实还有一种理解a和b都在队中的,只不过是指向了同一块内存区域,更倾向于这种理解。

我们来看一下运行时常量和编译时常量的区别

public static final int a = 10就是一个编译时常量,在编译后的符号中找不到a,所有对a 的引用都被替换成了20;它是不依赖于类的,在编译时就可以确定值。

public static final int b = "hello".length()就是一个运行时常量;它是依赖于类的,它的赋值会引起类的初始化。

归根结底还是javac的编译机制导致了这样的结果。当涉及到方法的调用时,必须在运行的时候才能确定结果

假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值