JVM方法区

方法区

栈,堆,方法区的交互关系:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

方法区的理解

方法区看作是一块独立于java堆的内存空间。(关系如台湾与中国)
方法区与java堆一样,是各个线程共享的内存区域。
方法去在JVM启动时被创建,并且和java堆一样在物理地址是可以不连续的。关闭时JVM释放这块区域内存。
方法区的大小和堆一样,可以选择固定或者可扩展。
方法区的大小决定了可以保存多少个类,如果系统定义过多类,会导致方法区移除。

jdk7及以前把方法区称为永久代,jdk8及以后使用元空间取代永久代。
元空间与永久代的区别:元空间使用本地主机内存。
在这里插入图片描述

设置方法区的大小与OOM

jdk7及以前:
-XX:PermSize来设置永久代的初始分配空间。默认27.5M
-XX:MaxPermSize来设置永久代的最大可分配空间。32为机器是64M,64为机器是82M。

jdk8及以后:
默认值依赖于平台,-XX:MetaspaceSize是21M,-XX:MaxMetaspaceSize的值是-1,没有限制。
初始内存空间大小称为高水位线,一旦触及这个高水位线,Full GC就会被触发卸载一些没用的类,然后高水位线会被重置,重置的大小由gc释放的空间决定。如果高水位线设置过低,就会平凡出发gc,建议设置为相对较高。

内存泄漏与内存溢出

内存溢出就是new的对象太多,而且这些对象都是有用的,不能够被垃圾回收掉。有想要new新的对象,由于堆内存不够,造成OOM。

内存泄露就是对象应该被回收,但是由于GCRoots仍然引用,导致垃圾回收器不能回收,一般而言是代码出现了问题,例如IO流没有关闭、ThreadLocal没有remove。
内存泄露就是存在引用指向已经不会再使用的对象,导致该对象不能被回收。
泄露就是说可使用的内存在逐步减小,溢出就是内存用满了。

方法区内部结构

在这里插入图片描述
方法区:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即使编译器编译后的代码缓存。
在这里插入图片描述

类型信息:

权限修饰符,全类名,父类全类名(例java.long.Object),实现多个的接口全类名(含泛型信息)。

域(Filed)信息:

域名称,域类型,域修饰符。
在这里插入图片描述

方法信息:

构造器信息(从字节码看方法信息中含有构造器),方法名称、返回值类型、方法修饰符、方法参数的数量和类型、方法的字节码、异常表。
构造器:
在这里插入图片描述
方法信息:
在这里插入图片描述
异常表信息:
在这里插入图片描述

静态变量和类关联在一起,随着类的加载而加载,他们成为类数据在逻辑上的一部分。
类变量被类的所有实例共享,即使没有类实例时你也可以访问它。
全局常量(static final)在编译时就被赋值了
在这里插入图片描述

常量池与运行时常量池

常量池:包含各种字面量和对类型、域、方法的符号引用。
在这里插入图片描述
小结:常量池可以看成一张表,虚拟机指令根据这张表找到要执行的类名、方法名、参数类型、字面量类型

运行时常量池是方法区的一部分。
常量池是class文件的一部分。用于存放编译期生成各种字面量和符号引用这部分内容在类加载结束后存放到方法区的运行时常量池中。

JVM为每个已加载的类型(类或接口)都会维护一个常量池。池中的数据像数组一样,通过索引访问。(#3)
运行时常量池另一重要特性:具有动态性

方法去演进细节

只有Hotspot才有永久代。JRockit、IBM不存在永久代概念。

  • jdk1.6及以前:用永久代,静态变量存放在永久代上。
  • jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中。
  • jdk8及以后:无永久代。类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

为什么要用元空间替换永久代?

1、永久代大小不好设定,小了容易Full GC造成性能降低或出现OOM,太大了造成内存空间浪费。
2、永久代调优比较困难。垃圾回收困难。

StringTable(字符串常量池)为什么要调整?

jdk7放在永久代中,永久代的回收效率很低,仅在Full gc才出发垃圾回收。在开发中会创建大量的字符串,回收效率低,会导致永久代内存不足。放在堆里(年轻代与老年代)回收内存。

方法区的垃圾回收

java虚拟机规范没有给出明确要求是否必须回收方法区。
(Full GC)方法区的垃圾回收:常量池中废弃的常量、不再使用的类型。比较困难。

Hotspot:只要常量池中的常量没有被任何地方引用,就可以回收。

判定类型不在使用比较苛刻:

  1. 该类的所有实例已经全部被回收,也就是java堆中不存在该类及其任何派生子类的实例。
  2. 加载该类的类加载器已经被回收。
  3. 该类对应java.long.Class(大class实例)对象没有在任何被引用过,无法在任何地方通过反射访问该类的方法。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值