IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> JVM运行时内存分区 -> 正文阅读

[系统运维]JVM运行时内存分区

什么是JVM?JVM概述——初识JVM(类加载器,垃圾回收器,执行引擎)

上一篇博客我们对jvm以及它的三个“部件”有了初步的认识,这一篇我们探讨一下源码经过编译、加载后这些数据被jvm分类存储在内存中,根据数据的特性,jvm从逻辑上把内存划分为以下几个区域:方法区、虚拟机栈、本地方法栈、程序计数器、堆。
在这里插入图片描述

程序计数器(线程私有)

程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。

如果当前线程正在执行一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;
如果正在执行的是Native方法,这个计数器的值为空。

程序计数器内存区域是唯一一个在jvm规范中没有规定任何OOM(OutOfMemoryError)情况的区域。

程序计数器为什么是线程私有?
由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,因此在任何一个确定的时刻,一个处理器(多核处理器则指的是一个内核)都会执行一条线程中的指令。因此为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各条线程之间计数器互不影响。

虚拟机栈(线程私有)

虚拟机栈描述的是java方法执行的内存模型:这部分区域主要是用于线程运行方法的区域,此区域属于线程私有的空间,每一个线程创建后都会申请一个自己单独的栈空间,每一个方法执行的同时都会创建一个栈帧用于存储表(保存着变量的数据)、操作数栈(进行运算时存放数据的空间)、动态链接(指向常量池的引用)、方法出口等信息。每个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出战的过程。声明周期与线程相同。
下面来模拟一下执行方法时进栈出栈的过程:

执行以下代码

public class JavaStackTest {
?
    public static void main(String[] args) {
        System.out.println("开始执行main方法");
        test1();
?
    }
?
    public static void  test1(){
        System.out.println("test1");
                test2();
    }
?
    public static void  test2(){
        System.out.println("test2");
    }
?
}

在这里插入图片描述

局部变量表

存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在执行期间不会改变局部变量表大小。

这个区域一共会产生以下两种异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),将会抛出StackOverFlowError异常。
  2. 虚拟机在动态扩展时无法申请到足够的内存,会抛OutOfMemoryError异常。

本地方法栈(线程私有)

当java需要与一些底层系统或硬件交互时,这个时候需要通过调用native本地方法实现,本地方法栈和虚拟机栈的作用差不多,区别无非是本地方法栈为虚拟机使用的native方法服务,而虚拟机栈为jvm执行的java方法服务。

方法区(线程共享)

方法区用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据

方法区、永久代、元空间的关系

方法区是jvm定义的一种规范,是所有虚拟机都要遵守的约定,而永久代和元空间都是实际某个虚拟机针对方法区的一种实现。永久代是JDK8之前Hotspot虚拟机对方法去的实现,也就是说在JDK8以前的Hotspot虚拟机中,方法区也被称为永久代,而在JDK8之后被元空间取代。

永久代和元空间的区别

要说他们的区别先贴上一张以前博客里的图
在这里插入图片描述
先说一下不管是永久代还是元空间他们都是Hotspot针对方法区的一种实现,两者最大的区别在于永久代是在jvm虚拟机中分配内存,即上图的左半部分,元空间则分配在本地内存中。
为什么要做这样一种改变呢?
因为很多类是在运行期间加载的,这部分类加载的空间不可控,如果这部分内存是在jvm内存里分配的话,分配太大那么jvm其他区域可用内存就会变小,如果分配太小,就容易出现方法区内存溢出。所以JDK8中选择把方法区分配在本地内存,这样做的好处是元空间的大小不会受限于虚拟机分配的内存大小,就不会那么容易出现内存溢出。

JVM规范规定:当方法区无法满足内存分配需求时,将抛出OOM异常

运行时常量池(方法区的一部分,线程共享)

这一部分区域主要存放静态变量,字面量,符号引用

字面量:字符串(JDK7之后移动到堆)、final常量、基本数据类型的值
符号引用:类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。

JDK6中所有常量池数据是存放在永久代中,但到JDK7之后Hotspot把永久代中的字符串常量、静态变量迁移到了堆中,后面的jdk8并没有对这部分内容进行迁移,在jdk8中字符串,静态变量数据还是放在堆中,所以常量池只是在jvm规范定义上属于方法区,但Hotspot在实现的时候一部分实际上保存在堆中了。

堆区(线程共享)

堆是jvm所管理的最大内存区域,在jvm启动时创建。此内存区域存放的都是对象实例。jvm规范中提到:所有对象实例以及数组都要在堆上分配。

堆是垃圾回收器管理的主要区域,因此很多时候称之为“GC堆”。根据jvm规范规定的内容,堆可以处于物理上不连续额内存空间中。堆在主流的虚拟机中都是可扩展的(-Xmx设置最大值,-Xms设置最小值)。

如果在堆中没有足够的内存完成实例分配并且堆也无法再拓展时,将会抛出OOM。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 11:10:24  更:2021-08-02 11:11:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 16:27:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码