JAVA JVM运行时数据区详解

目录
  • 一、前言
  • 二、运行时数据区整体概架构
  • 三、程序计数器
  • 四、虚拟机栈
    • 1、栈的特点
    • 2、栈帧的内部结构
    • 3、局部变量表
    • 4、操作数栈
    • 5、动态链接
    • 6、方法返回地址
  • 五、本地方法栈
  • 六、堆
    • 1、设置堆大小的参数
    • 2、对象分配过程
    • 3、堆中的GC
    • 4、内存分配策略
    • 5、什么是TLAB
    • 6、堆是分配对象存储的唯一选择吗?
  • 七、方法区
    • 1、方法区概述
    • 2、设置方法区内存大小
    • 3、如何解决OOM问题?
    • 4、方法区存储什么
    • 5、方法区的演进细节
    • 6、方法区的GC
  • 总结

一、前言

这是JVM系列文章的第三篇,这篇文章将对整个JVM运行时数据区和GC垃圾回收详细的介绍。这部分也算是JVM的核心内容了。

二、运行时数据区整体概架构

以下是自己的一句话总结:

分为线程私有和线程共享的两大类,其中程序计数器、虚拟机栈、本地方法栈是属于线程私有的,堆内存及方法区内存是线程共享的。程序计数器主要是记录字节码指令,CPU上下文切换线程,从一个线程切换到另一个线程,需要知道线程执行到哪一步,所以记录这个指令就是很有必要的,程序计数器无OOM和GC的发生。虚拟机栈里面是一个个栈帧,每一个栈帧对应着每一个方法,栈帧又是由局部变量表、操作数栈、方法返回值地址、动态链接组成。虚拟机栈可能会发生栈溢出异常,即starkoverflow本地方法栈是存放本地方法相关的东西;堆是一块很大的空间,整体分为2大块,新生代和老年代,新生代又分了Eden区、S0区、S1区,垃圾回收主要发生在新生代,每一个区对应不同的垃圾回收算法;方法区保存的是一些常量、类的基本信息等,方法区对应的实现在JDK7中是永久代,在JDK8中是元空间。

三、程序计数器

用来储存指向下一条指令的地址,是线程私有的,生命周期和线程的生命周期一致。

四、虚拟机栈

虚拟机栈是线程私有的,内部保存一个个栈帧,每一个栈帧对应一个Java方法的调用,生命周期和线程的生命周期保持一致。先来看看栈的特点。

1、栈的特点

栈是运行时的单位,而堆是存储的单位。栈的特点是先进后出,后进先出。

可以通过参数-Xss来设置栈空间大小

2、栈帧的内部结构

3、局部变量表

是一个数字数组,主要用于存储方法参数和定义在方法内的局部变量,这些数据类型包括各类基本数据类型,对象引用等,所需的容量大小是在编译期确定下来的,在方法运行期间是不会改变局部变量表大小的。

关于Slot的理解:

静态变量和局部变量的区别:

总结:

在栈帧中,与性能关系最为密切的就是局部变量表,在方法执行时,虚拟机使用局部变量表完成完成方法的传递,局部变量表中的数据也是可达性分析中的GC Root,如果一个对象在局部变量表中还有引用,那么根绝可达性分析算法,这个变量就不属于垃圾对象,是不会被GC回收的。

4、操作数栈

操作数栈是栈中栈,也可称为表达式栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈和出栈。主要用于保存计算过程的中间结果。操作数栈,可以看成是临时寄存器,计算过程中变量的临时保存

5、动态链接

方法重写的本质

6、方法返回地址

存放调用该方法的PC寄存器的值

五、本地方法栈

管理本地native本地方法,是线程私有的,所谓的本地方法,其实就是一些非Java语言写的代码,这部分代码甚至可以和操作系统CPU进行打交道。

六、堆

堆是内存管理的核心区域,是线程共享的,属于JVM级别,也就是一个JVM实例就会有一个堆空间,注意的是虽然堆整体上是线程共享的,但是在内部有一小块空间是线程私有的缓存区TLAB。

几乎所有的对象实例都是在堆中,堆是GC垃圾回收的重点区域。堆整体可以分为新生代和老年代,新生代又分为Eden区和S0和S1区。

新生代和老年代的比例是1:2,Eden区和s0,s1区所占空间比例是8:1:1

1、设置堆大小的参数

-Xms:用于表示堆区的起始内存,默认情况下,占物理内存大小的64分之一。

-Xmx用于表示堆区的最大内存,默认情况下,占物理内存的四分之一。

通常起始内存和最大内存两个参数设置成一样,目的是为了GC清理完堆区内存后不需要重新分隔
计算堆区的大小,从而提高性能。
查看设置的参数:
方式一:jps(查看进程)
            jstat -gc 进程id
方式二:-xx:+printGCDetails

2、对象分配过程

这里s0和s1谁是空的谁就是to,年龄计数器阈值是15,YGC是在Eden区满的时候会触发,s0和s1满的时候不会触发YGC,YGC会将s区以及伊甸园区一起GC

关于垃圾回收,频繁在新生区收集,很少在养老区收集,几乎不在永久区/元空间收集。

Visualvm是JVM常用调优工具,在JDK的bin下就可以打开

3、堆中的GC

年轻代(Minor GC)触发机制

老年代GC(Major GC/Full GC)触发机制

Full GC 触发机制

4、内存分配策略

5、什么是TLAB

TLAB表明堆不一定是共享的。

6、堆是分配对象存储的唯一选择吗?

如果经过逃逸分析,一个对象并没有逃逸出方法的话,那么就有可能被优化成栈上分配。

逃逸分析手段:

注意:JDK6U23版本后,HotSpot默认已经开启逃逸分析。所以我们得出一个结论,开发中能使用局部变量的,就不要使用在方法外定义。JDK7后字符串常量池和静态变量存储在堆中

七、方法区

方法区可以看做是一块独立于堆的内存空间,是线程共享的,主要存储类信息、运行时常量池等,也会发生OOM,JDK8前成为永久代,JDK8成为元空间。(元空间和永久代最大的区别是,元空间不再使用JVM内存,而是使用了本地内存技术)

1、方法区概述

2、设置方法区内存大小

3、如何解决OOM问题?

4、方法区存储什么

5、方法区的演进细节

6、方法区的GC

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • JVM运行时数据区划分原理详解

    Java内存空间 内存是非常重要的系统资源,是硬盘和cpu的中间仓库及桥梁,承载着操作系统和应用程序的实时运行.JVM内存布局规定了JAVA在运行过程中内存申请.分配.管理的策略,保证了JVM的高效稳定运行.不同的jvm对于内存的划分方式和管理机制存在着部分差异(对于Hotspot主要指方法区) (图源阿里)JDK8的元数据区+JIT编译产物 就是JDK8以前的方法区 JavaAPI中的Runtime public class Runtime extends Object Every Java

  • Java JVM运行时数据区(Run-Time Data Areas)

    1.官网概括 引用官网说法: The Java Virtual Machine defines various run-time data areas that are used during execution of a program. Some of these data areas are created on Java Virtual Machine start-up and are destroyed only when the Java Virtual Machine exits.

  • Java内存模型与JVM运行时数据区的区别详解

    首先,这两者是完全不同的概念,绝对不能混为一谈. 1.什么是Java内存模型? Java内存模型是Java语言在多线程并发情况下对于共享变量读写(实际是共享变量对应的内存操作)的规范,主要是为了解决多线程可见性.原子性的问题,解决共享变量的多线程操作冲突问题. 多线程编程的普遍问题是: 所见非所得 无法肉眼检测程序的准确性 不同的运行平台表现不同 错误很难复现 故JVM规范规定了Java虚拟机对多线程内存操作的一些规则,主要集中体现在volatile和synchronized这两个关键字. vo

  • JAVA JVM运行时数据区详解

    目录 一.前言 二.运行时数据区整体概架构 三.程序计数器 四.虚拟机栈 1.栈的特点 2.栈帧的内部结构 3.局部变量表 4.操作数栈 5.动态链接 6.方法返回地址 五.本地方法栈 六.堆 1.设置堆大小的参数 2.对象分配过程 3.堆中的GC 4.内存分配策略 5.什么是TLAB 6.堆是分配对象存储的唯一选择吗? 七.方法区 1.方法区概述 2.设置方法区内存大小 3.如何解决OOM问题? 4.方法区存储什么 5.方法区的演进细节 6.方法区的GC 总结 一.前言 这是JVM系列文章的第

  • 面试时必问的JVM运行时数据区详解

    目录 前言 正文 1.运行时数据区(Run-Time Data Areas) 1)程序计数器(Program Counter Register) 2)Java虚拟机栈(Java Virtual Machine Stacks) 3)本地方法栈(Native Method Stacks) 4)堆(Heap) 5)方法区(Method Area) 6)运行时常量池(Run-Time Constant Pool) 2.Java 中有哪几种常量池? 3.class 文件常量池 4.运行时常量池 5.字符串

  • java虚拟机运行时数据区分析

    JVMmemorymodel 这篇文章主要介绍在JVM规范中描述的运行时数据区(RuntimeDataAreas).这些区域设计用来存储被JVM自身或者在JVM上运行的程序所是用的数据. 我们先总览JVM,然后介绍下字节码,最后介绍不同的数据区域. 总览 JVM作为操作系统的抽象,保证同样的代码在不同的硬件或操作系统上的行为一致. 比如: 对于基本类型int,无论在16位/32位/64位操作系统上,都是一个32位有符号整数.范围从-2^31到2^31-1 无论操作系统或者硬件是大字节序还是小字节

  • JVM 运行时数据区与JMM 内存模型

    目录 1. JVM 运行时数据区 2. JMM 内存模型 硬件内存模型 JMM 3. 可见行与 volatile 关键字 1. JVM 运行时数据区 JVM运行时数据区可以分为元空间,堆,虚拟机栈,本地方法栈,程序计数器五大块. 元空间(方法区):存放类模版对象,是线程共享的区域,在磁盘上,一般不会GC 堆空间:线程共享的区域,对象创建与GC的主要阵地 虚拟机栈:线程私有的,基本组成单位是栈帧,每个栈帧对应一个方法,栈帧组成如下 局部变量表:存放方法变量信息 操作数栈:方法运行的区域 动态链接:

  • java程序运行时内存分配详解

    一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆,每一个线程有一个自己私有的栈.进程所创建的所有类的实例(也就是对象)或数组(指的是数组的本身,不是引用)都放在堆中,并由该进程所有的线程共享.Java中分配堆内存是自动初始化的,即为一个对象分配内存的时候,会初始化这个对象中变量.虽然Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配,也就是说

  • JVM运行时数据区原理解析

    前言 Java虚拟机定义了若干种程序运行期间会使用的运行时数据区域,其中一些会随着虚拟机启动而创建,随着虚拟机的退出而销毁.另外一些则是和线程一一对应,这些与线程对应的数据区域随着线程开始而创建,线程的结束而销毁. PC寄存器 PC寄存器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器,每条线程都要一个独立的PC寄存器,这个内存也是线程私有的内存.正在执行 java 方法的话,PC寄存器是记录的是虚拟机字节码指令的地址(当前指令的地址).如果还是 Native 方法,则为und

  • 深入理解Java运行时数据区_动力节点Java学院整理

    JVM体系结构和运行时数据区概述 要理解JVM的运行时数据区, 必须先要理解JVM的体系结构, 因为虚拟机的体系结构基本上解释了"为什么会有这些运行时数据区" . JVM的体系结构如下: 由此可见, 运行时数据区的划分, 是和JVM的体系结构相关的. 本文主要介绍运行时数据区的划分, 对体系结构不做深入的讲解. 简单概括一下, 类加载器子系统用于将class文件加载到虚拟机的运行时数据区中(准确的说应该是方法区) . 可以认为执行引擎是字节码的执行机制, 一个线程可以看做是一个执行引擎

  • Java运行时数据区概述详解

    Java 虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途,如图所示: 程序计数器 程序计数器是一块比较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器. 在虚拟机的概念模型中(仅是概念模型,各种虚拟机可能会通过一些更加高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都需要依赖这个计数器来完成. 如果线程正在执行一个Java方法,则这个计数

随机推荐