【JVM第四篇--运行时数据区】堆

本文详细介绍了JVM的堆内存结构,包括堆的细分:新生代、老年代、元空间(Java8之后替代永久代),以及对象在堆中的分配过程。文章还探讨了不同类型的垃圾收集(MinorGC、MajorGC、FullGC)及其触发条件,并讨论了内存分配策略,如TLAB。此外,逃逸分析的概念和作用也在文中得到阐述,展示了如何通过逃逸分析优化内存分配和提升性能。
摘要由CSDN通过智能技术生成

写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记。其观看地址如下:尚硅谷2020最新版宋红康JVM教程

一、堆的概述

JVM的运行时数据区如下:
在这里插入图片描述

一个Java程序运行起来对应着一个进程(操作系统的进程),一个进程对应着一个JVM实例。而一个JVM实例就对应着一个运行时数据区,则其中就包含着一个堆空间。一个进程中的多个线程共享这个堆空间。
几乎所有的对象实例和数组都在堆上分配内存(并非所有的对象都是在堆上分配内存,后面会提到这一特殊情况),即堆空间存储着绝大部分的对象。虚拟机栈中的栈帧保存着数组或者对象的引用,这个引用就指向对象或者数组在堆中的位置。

有代码如下:

package com.fengjian.www.RunDataArea.Heap;

public class simpleHeap {
   
    
    private int id;

    public simpleHeap(int id){
   
        this.id = id;
    }

    public void show(){
   
        System.out.println("my id is:"+id);
    }

    public static void main(String[] args) {
   
        simpleHeap s1 = new simpleHeap(1);
        simpleHeap s2 = new simpleHeap(2);
    }
}

代码对应下图,

在这里插入图片描述

二、堆内存的细分

堆,是垃圾回收(GC,Garbage Collection,垃圾收集)的重点区域。我们常说的虚拟机的GC,大部分都与堆有关。
在一个Java方法结束后(即在虚拟机栈中出栈后,再没有引用指向堆中的对象),堆中的对象并不会马上被移除,而是在GC时才会被移除。
由于现代垃圾收集器大部分都基于分代收集理论设计,所以堆空间在逻辑上细分如下:

(1)、Java7及之前,分为三部分:新生代、老年代、永久代
① 新生代: Yonug/New Generation Space

其中,新生代划分为一个Eden区(伊甸园区)和两个Survivor区(From Survivor和To Survivor)

②老年代:Tenure/Old Generation Space

③永久代:Perm Space

(2)、Java8及之后,也分为三部分:新生代、老年代、元空间
Java8之后,取消了永久代,改用元空间代替,而新生代和老年代则继续保留。
元空间:Mete Space
后面将详细介绍永久代和元空间的区别。

值得注意的是,虽然这里将永久代、元空间和新生代、老年代并列,但实际上,永久代和元空间都不属于堆空间的一部分。事实上,永久代和元空间是方法区的实现方式,即用永久代或者元空间来实现方法区
堆空间分出了一部分内存给永久代来实现方法区,而元空间则脱离了虚拟机内存,直接使用计算机的本地内存作为自己的空间。所以,我们常说的堆空间,本质上只包含新生代和老年代的空间。

示意图如下,
在这里插入图片描述
在这里插入图片描述

在我们常见的表述中,新生代、年轻代和新生区意思相同,老年代、老年区和养老代也都是一个意思,只是叫法不同而已。

1、永久代简述

我们现在开发常用的SunJDK和OpenJDK都是采用的HotSpot虚拟机。而永久代就独属于HotSpot虚拟机独有的,其他虚拟机则并没有。
HotSpot虚拟机采用了永久代来实现方法区。
方法区是虚拟机运行时数据区域的一块,是虚拟机规范中规定要有的一块区域。但是对于如何实现这块区域,虚拟机规范并没有给出。所以各个虚拟机厂商可以自主的实现这一区域。即方法区是一个规范,永久代是HotSpot虚拟机实现方法区的一种方式,后又用元空间来代替元空间。

使用永久代的好处有:
①由于永久代和新生代、老年代是连续的物理内存区域,故HotSpot虚拟机的垃圾回收器可以像管理堆一样管理方法区,省去了专门为方法区设置垃圾回收的工作。
②永久代和老年代的垃圾回收是绑定的,一旦其中一个区域被占满,这两个区域都会进行垃圾回收。

永久代的缺点也很明显:
①在Java7之前,HotSpot虚拟机将纳入字符串常量池的字符串(占用内存较大)存储在永久代中,导致了一系列的性能问题和内存溢出错误。(在Java7时,已经字符串常量池放到了堆中)
②永久代的大小指定困难,太小容易出现永久代溢出,太大容易导致老年代溢出。(可用:java-XX:PermSizejava-XX:Perm设置)

由于永久代容易导致javaOutofMemoryError,因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。故决定用元空间的设置来取代永久代。
当然,其实还有一个重要的原因就是,要合并HotSpot虚拟机和JRockit虚拟机的代码,JRockit没有永久代的设计&#

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值