Java学习笔记——JVM快速入门(二)

      本文将主要介绍JVM的方法区、栈和堆。堆区和方法区(元空间)是全局共享的,栈、本地方法栈、程序计数器是线程私有的

一、方法区

      方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间。
      静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关
      static final Class 常量池

二、栈

      1.先进后出,类似于桶
      2.主管程序的运行,生命周期和线程同步。栈是线程私有的,不能实现线程之间的共享。
      3.每当方法被调用时,栈都会创建一个栈帧(存储方法索引、输入输出参数、本地变量等),栈帧存储样式如下所示。

在这里插入图片描述
      4.程序正在执行的方法一定在栈的顶部。
      5.栈不存在垃圾回收问题
栈中存储的内容
      八大基本类型(byte、short、int、long、float、double、char、boolean)、对象引用、实例方法
对象的引用放在栈中,真正存放对象实例的位置是堆。下面将介绍堆。

三、堆

1.三种JVM

      Sun公司   HotSpot Java HotSpot( TM)64-Bit Server VM (build 25.181-b13,mixed mode)
      BEA JRockit
      IBM J9 VM
我们学习的都是HotSpot

2.堆

      Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。
      类加载器读取了类文件后,一般会把什么东西放到堆中?类、方法、常量、变量,保存我们所有引用类型的真实对象。
      在Java7及之前,堆内存在逻辑上可分为三部分,即新生区+养老区+永久区,不过在Java8之后变成了新生区+养老区+元空间。这里,就先以Java7中的堆内存为例来讲述。
在这里插入图片描述

1>新生区
      新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生区又分为两部分:伊甸区(Eden Space)和幸存者区(Survivor Space),所有的类都是在伊甸区被new出来的。幸存区有两个:0区和1区(0区和1区是会发生交换的,称作from和to会更为恰当,接下来讲到垃圾回收算法中的复制算法时再进行说明,这里先提一下)。
      当伊甸区的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸区进行垃圾回收 (轻量级垃圾回收即Minor GC),将伊甸区中的不再被其他对象所引用的对象进行销毁,然后将伊甸区中的剩余对象移动到幸存0区。
      若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。
      那如果1区也满了呢?再对该区进行垃圾回收,然后移动到养老区,不过,默认要经历15次Minor GC,才能进行养老区,大多数对象全都在新生区就被回收掉了。
      若养老区也满了,那么这个时候将产生重量级垃圾回收(也即Full GC),进行养老区的内存清理。
      若养老区执行了Full GC之后发现依然无法进行对象的保存,就会产生OOM异常(也即OutOfMemoryError,内存溢出错误)。
2>老年代
      老年代主要存放JVM认为生命周期比较长的对象(经过几次的Young Gen的垃圾回收后仍然存在),内存大小相对会比较大,垃圾回收也相对没有那么频繁。
3>永久区
      这个区域是常驻内存的,用来存放JDK自身携带的Class对象Interface元数据,存储的是Java运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭VM就会释放这个区域的内存。
      出现OOM的情况,①一个启动类,加载了大量的第三方jar包;②Tomcat部署了太多的应用,大量动态生成反射类。
注意:JVM是一直在更新的

  • jdk1.6之前:有永久代,常量池在方法区
  • jdk1.7:有永久代,但是慢慢的退化了,提出"去永久代",常量池在堆中
  • jdk1.8之后:无永久代,常量池在元空间

补充:真实物理上的划分
在这里插入图片描述
      元空间物理上不存在,逻辑上存在,所以很多人将元空间称为非堆,新生代+老年代称为堆。
      VM options:-Xms1024m -Xmx1024m -XX:+PrintGCDetails

public class Demo{
	public static void main(String[] args){
		//返回虚拟机试图使用的最大内存
		long max = Runtime.getRuntime().maxMemory();
		//返回jvm的初始化总内存
		long total = Runtime.getRuntime().totalMemory();
		
		System.out.println("max="+max+"字节\t"+(max/(double)1024/1024)+"MB");
		System.out.println("total="+max+"字节\t"+(total/(double)1024/1024)+"MB");
	}
}

在这里插入图片描述
      305664K(新生区) + 699392K(老年区) = 1005056K = 981.5M,还没有加元空间的内存,就已经等于总的了,所以元空间物理上不存在于jvm中,元空间实际上存在于本地内存。这意味着不会再java.lang.OutOfMemoryError: PermGen问题,也不再需要你进行调优及监控内存空间的使用。
      元空间与方法区之间的关系是:元空间就是方法区的一个具体实现,而方法区就是一个接口。
      新生区中的伊甸区、幸存0区以及幸存1区的比例是8:1:1。

参考资料
1.快速入门JVM第一讲——JVM体系结构概述
2.【狂神说Java】JVM快速入门篇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值