JVM之运行时数据区

news2024/9/21 0:27:16

 Java虚拟机在运行时管理的内存区域被称为运行时数据区。

  程序计数器: 也叫pc寄存器,每个线程会通过程序计数器记录当前要执行的字节码指令的地址。程序计数器在运行时是不会发生内存溢出的,因为每个线程只存储一个固定长度的内存地址。

  JAVA虚拟机栈:采用栈的数据结构来管理方法调用中的基本数据,先进后出,每一个方法的调用使用一个栈帧来保存。JAVA虚拟机栈随着线程的创建而创建,而回收则会在线程的销毁时进行。由于方法可能会在不同线程中进行,每个线程都会包含一个自己的虚拟机栈。

 栈帧的组成:

   1、局部变量表:是在运行过程中存放所有的局部变量。栈帧中的局部变量表是一个数组,数组中每一个位置称之为槽,long和double类型占2个槽,其他类型占用1个槽。实例方法中的序号为0的位置存放的是this,指的是当前调用方法的对象,运行时会在内存中存对实例对象的地址。

   2、操作数栈:是栈帧中虚拟机在执行指令过程中用来存放临时数据的一块区域。

   3、帧数据:主要包含动态链接、方法出口、异常表的引用。当前类的字节码指令引用了其他类的属性或方法时,需要将符号引用转换成对应的运行时常量池中的内存地址。动态链接就保存了编号到运行时常量池的内存地址的映射关系。

        方法出口是指在方法正确或异常结束时,当前栈帧会被弹出,同时程序计数器应该指向上一个栈帧中的下一条指令的地址。所以当前栈帧中需要存储此方法出口的地址。

        异常表存放的是代码中异常的处理信息,包含了异常捕捉的生效范围以及异常发生后跳转到的字节码指令位置。 

    如果栈帧过多,占用内存超过栈内存可以分配的最大大小就会出现内存溢出。如果我们不指定栈的大小,jvm将创建一个具有默认大小的栈。大小取决于操作系统和计算机的体系结构。 可以使用虚拟机参数 -Xss设置java虚拟机栈的大小。单位为字节(默认为字节,必须是1024的倍数)、k或kb、m或mb、g或gb格式: -Xss1024k 与-Xss类似,也可以使用-XX:ThreadStackSize调整标准来配置堆栈大小。 格式:-XX:ThreadStackSize=1024  。 hotshot虚拟机对栈的内存要求有最大最小限制。Windows(64位)下jdk8测试最小值为180k,最大值为1024m。

本地方法栈:

   JAVA虚拟机栈存储了JAVA方法调用时的栈帧,而本地方法栈存储的是c++编写的native本地方法的栈帧。在hotshot虚拟机中,JAVA虚拟机栈和本地方法栈实现上使用了同一个栈空间。

堆:

 一般JAVA程序中堆内存是空间最大的一块内存区域。创建出来的对象都存在于堆上。

 栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通个静态变量就可以实现对象在线程之间的共享。堆内存大小有上限,会发生内存溢出。堆空间有3个需要关注的值:used total max。这3个值可以通过arthas的dashboard看到。 

used:指的是当前已使用的堆内存。      total:是JAVA虚拟机已经分配的可用堆内存。

max是java虚拟机可以分配的最大堆内存。

测试代码:

package org.example.heap;

import java.io.IOException;
import java.util.ArrayList;

public class OverFlowError {
    public static void main(String[] args) throws IOException {

        ArrayList<Object> objects = new ArrayList<>();
        while (true){
            System.in.read();
            System.out.println("添加一次");
            objects.add(new byte[1024*1024]);
        }
    }
}

  在arthas上通过 dashboard -n 1 命令输出一次面板信息

  在中间的Memory栏 就有 used   total   max   usage   GC这5栏信息。

也可以直接输入memory 命令,只查看Memory的信息。

随着堆中对象增多,used逐渐接近total的值。当total内存即将不足时,JAVA虚拟机会继续分配内存给堆,但total有上限,最大只能与max相等。并不是当used=max=total时,堆内存才会溢出。堆内存溢出判断条件比较复杂,在total快接近max时就会发生内存溢出,并不会相等。如果不设置虚拟机参数,max默认是系统内存的四分之一,total默认是系统内存的64分之一。在实际应用中一般都需要设置total和max的值。

要修改堆的大小,可以使用参数-Xmx(max最大值)和-Xms(初始的total)。单位:字节(默认,必须是1024的倍数)、k或kb、m或mb、g或gb。限制:Xmx必须大于2mb,Xms必须大于1mb。 语法:-Xmx值 -Xms值

 下面看个实例,通过虚拟机参数对上面的代码程序设置堆的使用限制:  -Xmx200m  -Xms200m

然后在次启动arthas(注意-Xmx不要设置的太小,否则都不够arthas启动的,arthas启动就会报错)查看memory面板

我们发现对应的max值并不是我们设置的200m,而是小于200m的192m。

为什么arthas中显示的heap堆大小小于咱们设置的大小呢?

arthas中的heap堆内存使用了JMX技术中内存获取方式,这种方式与垃圾回收器有关,计算的是可以分配对象的内存,而不是整个内存。

JAVA服务端程序开发时,建议将-Xmx和-Xms设置为相同的值,这样在程序启动后可使用的总内存就是最大内存,而无需向JAVA虚拟机再次申请,减少了申请并分配内存时间上的开销,同时也不会出现内存过剩之后的堆收缩的情况。

 

  方法区: (是一个虚拟概念,每款JAVA虚拟机上都各不相同,jdk8之后的版本,将方法区存放在元空间中,元空间位于操作系统维护的直接内存中,独立于JAVA虚拟机内存之外)。默认情况下只要不超过操作系统承受的上限,可以一直分配,可以使用-XX:MaxMetaspaceSize=值  将元空间最大大小进行限制(没有过高要求时,一般设为256m)。

方法区存放基础信息,线程共享,主要包括三部分内容:

 1、类的元信息:保存了所有类的基本信息(元信息),一般称之为InstanceKlass对象,在类的加载阶段完成。

 2、运行时常量池:保存了字节码文件中的常量池内容。通过编号查表方式找到常量,这种常量称为静态常量池。当常量池加载到内存中,可以通过内存地址快速定位到常量池中的内容,这种常量池称为运行时常量池。

 3、字符串常量池:保存了字符串常量。存储在代码中定义的常量字符串内容。

jdk7以前(不包括7)字符串常量池是属于运行时常量池的一部分,他们存储的位置一致。后续做了调整,jdk7后将字符串常量池拿到了堆中。(逻辑上,字符串常量池存在在方法区,但从物理存储地址看,是存放在堆中)jdk7及以后,静态变量和字符串常量池都是存放在堆中的。

下面看个例子:

package org.example.method;

public class StringTable {
    public static void main(String[] args) {
        String a="1";
        String b="2";
        String c="12";
        String d=a+b;
        System.out.println(c==d);
        String e="1"+"2";
        System.out.println(c==e);
    }
}

执行结果是c==d为false,c位于方法区的字符串常量池中,d是创建了一个String对象,存放在了堆中。查看字节码文件可以看出 在创建d时是用的new方法创建了一个对象,而c是定义了一个属性    

     c==e为true。e是直接引用的字符串常量池中的c的值。

下面我们在看个例子,先介绍一下string.inturn方法 作用是可以手动的将字符串放入字符串常量池中。jdk7及以后,由于字符串常量池在堆上,所以intern方法会把第一次遇到的字符串的引用(存放在堆中的引用)放入字符串常量池。若字符串常量池中已经有该字符串就会返回常量池中的该字符串。

package org.example.method;

public class StringIntern {
    public static void main(String[] args) {
        //创建一个存放在堆中的对象
        String s1=new StringBuilder().append("think").append("123").toString();
        //s1.intern获取到的是字符串常量池中存放的对堆中的引用,所以为ture
        System.out.println(s1.intern()==s1);

        // 创建一个存放与于堆上的对象
        String s2=new StringBuilder().append("ja").append("va").toString();
        //由于在启动时就会在字符串常量池中放入“Java”
        //所以s2.intern获取到的是字符串常量池中存放的Java
        System.out.println(s2.intern()==s2);


    }
}

结果是s1的为true,s2的为false 。s1是因为字符串常量池中没有字符串“think123”,所以inturn方法返回的是对堆中该字符串对象的引用,也就是引用的堆中的s1对象。s2是因为程序启动时会自动的在字符串常量池中存放字符串“Java”,所以s2.inturn返回的是字符串常量池中的字符串,而s2是堆中的字符串对象。

直接内存:

  直接内存并不在《JAVA虚拟机规范》中,所以不属于JAVA运行时的内存区域。在jdk1.4中引入了NIO机制,使用了直接内存,只要解决俩个问题:

 1、JAVA堆中的对象如果不再使用要回收,回收时会影响对象的创建和使用。

 2、IO操作,比如读取文件,需要先把文件直接读入直接内存(缓冲区)在把数据复制到JAVA堆中。现在直接放入直接内存即可,同时在JAVA堆中维护直接内存的引用,减少了数据复制的开销。直接内存的空间有上限,会发生内存溢出。如果需要手动调整直接内存的大小,可以使用        -XX:MaxDirectMemorySize=值   单位k或K表示千字节,m或M表示兆字节,g或G表示千兆字节。默认不设置该参数时,jvm自动选择最大分配的大小。

元空间(也就是方法区)使用本机直接内存,不再位于java虚拟机内存中,不受堆的大小限制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1666657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[蓝桥杯 2021 国 ABC] 123(java)——前缀和,思维

目录 题目 解析 代码 这么久了&#xff0c;我终于能不看别人代码完整写出来了&#xff0c;呜呜呜。虽然过程也是很曲折。 题目 解析 这个题&#xff0c;找其中数列的规律&#xff0c;1,1,2,1,2,3,1,2,3,4&#xff0c;...&#xff0c;因此我们把拆分成行列&#xff0c;如下…

Qt---信号和槽

一、信号和槽机制 所谓信号槽&#xff0c;实际就是观察者模式。当某个事件发生之后&#xff0c;比如&#xff0c;按钮检测到自己被点击了一下&#xff0c;它就会发出一个信号&#xff08;signal&#xff09;。这种发出是没有目的的&#xff0c;类似广播。如果有对象对这个信号…

车载测试和传统测试有什么区别

搞清楚车载测试和传统应用测试的区别,就可以大胆冲冲冲! 车载测试随着市场的需求量增加又火来一波,一直’遥遥领先’的我们一定要告诉大家一个事实:车载测试和传统的应用测试是有很大区别的. 测试对象不一样 传统测试:测试的对象无非就是各种应用,比如电脑端的web系统(使用浏…

Git系列:git tag 使用技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

FANUC机器人坐标系的分类和简介

1、概述 坐标系是为了确定机器人的位置和姿势而在机器人或空间上定义的位置指标系统&#xff0c;坐标系分为关节坐标系和直角坐标系&#xff0c;直角坐标系遵循右手定则&#xff0c;而关节坐标系则是以机器人每个轴所转动的角度来表示机器人当前的位置。 2、坐标系的分类及简…

weblogic 反序列化 CVE-2018-2628

这个漏洞因为java版本问题一直下载不了ysoserial反序列化工具&#xff0c;没办法生成payload。这里记录一下漏洞原理。 一、漏洞简介 Weblogic Server中的RMI 通信使用T3协议在Weblogic Server和其它Java程序&#xff08;客户端或者其它Weblogic Server实例&#xff09;之间传…

团结引擎+OpenHarmony 3 通信

团结引擎和鸿蒙之间通信 因为 ts 并没有像 JAVA 有反射的调用&#xff0c;所以我们必须要像 Web GL 平台一样通过导出的行为告诉引擎到底哪些 ts 的接口可以给 C# 来调用。 1 在 Tuanjie 引擎里 需要一个tsllib文件&#xff0c;用于设置给导出对象 C#使用。就可以直接创建以 …

Unity基础

概述 基础知识 3D教学 数学计算公共类Mathf 练习: 三角函数 练习&#xff1a; Unity中的坐标系 Vector3向量 向量模长和单位向量 向量加减乘除 练习&#xff1a; 向量点乘 向量叉乘 向量插值运算 Quaternion四元数 为何要使用四元数 四元数是什么 四元数常用方法 四元数计算 练…

GeoServer安装以及部署

GeoServer介绍 GeoServer是一个开源的服务器软件&#xff0c;用于共享和编辑地理空间数据。它支持多种地理空间数据格式&#xff0c;并且可以发布为多种服务格式&#xff0c;如Web Feature Service (WFS)、Web Map Service (WMS)、Web Coverage Service (WCS)&#xff0c;以及…

十二、Redis主从复制

与其他的中间件存在同样的问题&#xff0c;在单机的情况&#xff0c;随着业务的增长&#xff0c;会面临着灾备、性能方面的压力。Redis在这方面提供了一主一从、一主多从的结构。这种结构同时也是实现读写分离功能的基础。即主节点提供写能力&#xff0c;从节点提供读能力。为了…

【C/C++】C/C++ 车票售票系统设计与实现(源码+课件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

初识C语言——第十八天

循环while/do while while 语法结构 while(表达式) 循环语句; break:在while循环中&#xff0c;break用于永久的终止循环 continue:在while循环中&#xff0c;continue的作用是跳过本次循环continue后面的代码 直接去判断部分&#xff0c;看是否进行下一次循环。 注意事项…

射频识别技术RFID

射频识别技术RFID RFID介绍 射频识别&#xff1a; 英文名称是(Radio Frequency Identification)&#xff0c; 简称是“ RFID” 又称 无线射频识别&#xff0c; RFID是物联网的其中一种终端技术。 RFID是一种通信技术&#xff0c; 可通过无线电讯号耦合识别特定目标并读写相关…

保研机试之【二叉树后序】--1道题

参考&#xff1a;东哥带你刷二叉树&#xff08;后序篇&#xff09; | labuladong 的算法笔记 建议先过一遍&#xff1a;今天是二叉树~-CSDN博客&#xff0c;very重要&#xff01; 然后再过一遍&#xff08;理解怎么应用方法&#xff09;&#xff1a;保研机试之[三道二叉树习题…

简单易懂的Java Queue入门教程!

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

7. path路径绘制:使用path绘制曲线

曲线在SVG中通常是通过贝塞尔曲线命令来绘制的&#xff0c;包括二次贝塞尔曲线&#xff08;Q&#xff09;和三次贝塞尔曲线&#xff08;C&#xff09;。这些命令允许我们创建平滑的曲线路径。 贝塞尔曲线的原理 贝塞尔曲线的基本原理是通过控制点和锚点来定义一条曲线的形状。…

微服务下的技术栈架构解析

微服务是一种架构风格&#xff0c;它将一个复杂的应用拆分成多个独立自治的服务&#xff0c;每个服务负责应用程序中的一小部分功能。这些服务通过定义良好的API进行通信&#xff0c;通常是HTTP RESTful API或事件流。微服务架构的主要特点包括单一职责、自治性、可独立部署和扩…

14.跳跃游戏Ⅱ

文章目录 题目简介题目解答解法一&#xff1a;贪心算法动态规划代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 跳跃游戏Ⅱ 相关的讲解&#xff01;&#x1f600; 题目简介 题目解答 解法一&#xff1a;贪心算法动态规划…

03c++继承与多态

目录&#xff1a; 继承的本质和原理派生类的构造过程重载覆盖 隐藏静态绑定和动态绑定多态 vfptr和vftable抽象类的设计原理多重继承以及问题虚基类 vbptr和vbtableRTTIc四种类强转继承多态常见笔试面试题目分享 1、继承的本质和原理&#xff1a; 继承方式&#xff1a; 基类…