JVM进阶(2)

一)方法区:

JVM进阶(2)_第1张图片

JVM进阶(2)_第2张图片

 java虚拟机中有一个方法区,该区域被所有的java线程都是共享,虚拟机一启动,运行时数据区就被开辟好了,官网上说了方法区可以不压缩还可以不进行GC,JAVA虚拟机就相当于是接口,具体的HotSpot就是虚拟机的实现,因为永久代还是使用的是JAVA虚拟机的内存,

方法区域可以是固定大小的,也可以根据计算的需要扩展,如果不需要更大的方法区域,则可以收缩,物理上是不连续的,在逻辑上是连续的;

JVM进阶(2)_第3张图片

1)方法区和JAVA堆一样,是各个线程共享的内存区域

2)方法区在JVM启动的时候就被创建,并且它的实际的物理内存空间和JAVA队去一样都可以是不连续的

3)方法区的大小和堆空间一样,可以选择固定大小或者是可扩展

4)方法去的大小决定了系统可以保存多少各类,如果系统定义了太多的类,导致方法去溢出,虚拟机同样也会抛出内存溢出错误,java.lang.OutOfMemory:perm space(永久代空间溢出)或者是java.lang.OutOfMemeory:MeatSpace(元空间空间溢出),比如说大量加载第三方jar包,Tomact部署的工程过多,大量的动态生成反射类,加载大量第三方jar包,Tomact部署的应用程序太多,一个简单的代码可能要加载很多类,动态生成反射类,比如说动态代理,元空间不在虚拟机设置的内存中,而是使用本地内存物理内存,字符串常量池和静态变量也会变化,但是如果超过本地内存上限,也会发生OOM metaSpace,因为方法区是不共享的,所以说只能有一个类可以调用类加载器实现类加载;

JVM进阶(2)_第4张图片

5)关闭JVM就会释放这个区域的内存,JDK7以前,习惯上把方法区称之为是永久代,JDK8开始使用元空间替代了永久代,本质上方法区和永久代并不是等价的,但是仅仅是针对于HotSpot虚拟机而言的;也就是JAVA虚拟机规范,对于如何实现方法区不会做统一要求,现在来看使用永久代共容易出现OOM;

6)元空间的本质和永久代类似,都是对JVM规范中方法去的实现,不过元空间和永久代最大的区别在于元空间不在虚拟机设置的内存中,二时使用的是本地内存,永久代和元空间不光名字变了,况且内部结构也调整了,根据JAVA虚拟机规范规定,如果方法去无法满足新的内存分配的需求的时候,会抛出OOM异常,本地内存是无限大的,况且静态变量字符串常量池等等也会变化;

-XX:MetaspaceSize=100m,-XX:MaxMetaspaceSize=100m

JVM进阶(2)_第5张图片

JVM进阶(2)_第6张图片

一般在实际开发中会进行设置MetaspaceSize,不会设置MaxMetaspaceSize是默认值-1即可,这个Metaspace一开始要设置的大一些,为了避免频繁的发生FullGC导致调整水平线

JVM进阶(2)_第7张图片

方法区用于存放已经被虚拟机加载的类型信息,常量,静态变量以及即时编译器编译过后的代码缓存

1)类型信息:对于每一个加载的类型(类 class,接口 interface,枚举Enum,注解 annoation),JVM必须在方法中存放一下类型信息:

1)这个类型的完整有效名称(全名=包名+类名)

2)这个类型直接的父类的完整有效名字(对于interface和java.lang.object,都是没有父类的)

3)这个类型的修饰符

4)这个类直接接口的有效列表

2)域信息:就是成员变量的属性,JVM必须在方法区中保存类型的所有域的相关信息以及域的声明顺序,域的相关信息包括,修饰符,关键字等等,名称类型,修饰符,在方法区中也是保留着这个类信息是被哪一个类加载器加载进来的,类加载器的信息也是在类的信息中是有纪录的,同时类加载也会记录他都加载过那些类,彼此相互记录;

3)方法信息:操作数栈的深度,方法的权限,形参,局部变量表的深度,以及try catch包裹的代码范围信息;

JVM进阶(2)_第8张图片

JVM进阶(2)_第9张图片

上面的这段代码执行也不会出现空指针异常,被static和final修饰的量是在编译过程中的准备阶段就被附上初值了

你可能感兴趣的:(jvm)