范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

JVM运行数据区深度解析

  运行数据区
  字节码只是一个二进制文件存放在那里。要想在jvm里跑起来,先得有个运行的内存环境。
  也就是我们所说的jvm运行时数据区。
  1)运行时数据区的位置
  运行时数据区是jvm中最为重要的部分,执行引擎频繁操作的就是它。类的初始化,以及后面我们讲的对象空间的分配、垃圾的回收都是在这块区域发生的。
  2)区域划分
  根据《Java虚拟机规范》中的规定,在运行时数据区将内存细分为几个部分
  线程私有的:Java虚拟机栈(Java Virtual Machine Stack)、程序计数器(Program Counter Register)、本地方法栈(Native Method Stacks)
  大家共享的:方法区(Method Area)、Java堆区(Java Heap)
  接下来我们分块详细来解读,每一块是做什么的,如果溢出了会发生什么事情 1.1 程序计数器1.1.1 概述
  程序计数器(Program Counter Register) 每个线程一个。是一块较小的内存空间,它表示当前线程执行的字节码指令的地址。 字节码解释器工作时,通过改变这个计数器的值来选取下一条需要执行的字节码指令,所以整个程序无论是分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。 由于线程是多条并行执行的,互相之间执行到哪条指令是不一样的,所以每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为"线程私有"的内存。 如果是native方法,这里为空 1.1.2 溢出异常
  没有!
  在虚拟机规范中,没有对这块区域设定内存溢出规范,也是唯一一个不会溢出的区域 1.1.3 案例
  因为它不会溢出,所以我们没有办法给它造一个,但是从class类上可以找到痕迹。
  回顾上面javap的反汇编,其中code所对应的编号就可以理解为计数器中所记录的执行编号。
  1.2 虚拟机栈
  1.2.1 概述也是线程私有的!生命周期与线程相同。 它描述的是Java方法执行的当前线程的内存模型,每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 1.2.2 溢出异常
  1)栈深度超出设定
  如果是创建的栈的深度大于虚拟机允许的深度,抛出
  Exception in thread "main" java.lang.StackOverflowError
  2)内存申请不足
  如果栈允许内存扩展,但是内存申请不够的时候,抛出 OutOfMemoryError
  注意!这一点和具体的虚拟机有关,hotspot虚拟机并不支持栈空间扩展,所以单线程环境下,一个线程创建时,分配给它固定大小的一个栈,在这个固定栈空间上不会出现再去扩容申请内存的情况,也就不会遇到申请不到一说,只会因为深度问题超出固定空间造成上面的StackOverflowError
  如果换成多线程,毫无节制的创建线程,还是有可能造成OutOfMemoryError。但是这个和Xss栈空间大小无关。是因为线程个数太多,栈的个数太多,导致系统分配给jvm进程的物理内存被吃光。
  这时候虚拟机会附带相关的提示:
  Exception in thread "main" java.lang.OutOfMemoryError: unable to create native thread
  ps: 每个线程默认分配1M空间(64位linux,hotspot环境)
  疑问:是不是改小Xss的值就可以得到栈空间溢出呢?
  答:根据上面的分析,hotspot下不可以,还是会抛出StackOverflowError,无非深度更小了。 1.2.3 案例一:进出栈顺序
  1)代码 package com.itheima.jvm.demo; /** * 程序模拟进栈、出栈过程 * 先进后出 */public class StackInAndOut {    /**     * 定义方法一     */    public static void A() {        System.out.println("进入方法A");    }     /**     * 定义方法二;调用方法一     */    public static void B() {        A();        System.out.println("进入方法B");    }     public static void main(String[] args) {         B();        System.out.println("进入Main方法");    }}
  2)运行结果: 进入方法A进入方法B进入Main方法
  3)栈结构:
  main方法---->B方法---->A方法
  1.2.4 案例二:栈深度溢出
  1)代码
  这个容易实现,方法嵌套自己就可以: package com.itheima.jvm.demo; /** * 通过一个程序模拟线程请求的栈深度大于虚拟机所允许的栈深度; * 抛出StackOverflowError */public class StackOverFlow {    /**     * 定义方法,循环嵌套自己     */    public static void B() {        B();        System.out.println("进入方法B");    }     public static void main(String[] args) {         B();        System.out.println("进入Main方法");    }}
  2)运行结果: Exception in thread "main" java.lang.StackOverflowError	at com.itheima.jvm.demo.StackOverFlow.B(StackOverFlow.java:12)	at com.itheima.jvm.demo.StackOverFlow.B(StackOverFlow.java:12)	at com.itheima.jvm.demo.StackOverFlow.B(StackOverFlow.java:12)	at com.itheima.jvm.demo.StackOverFlow.B(StackOverFlow.java:12)	at com.itheima.jvm.demo.StackOverFlow.B(StackOverFlow.java:12)
  3)栈结构:
  1.2.5 案例三:栈内存溢出
  一直不停的创建线程就可以堆满栈
  但是!这个很危险,到32系统的winxp上勇敢的小伙伴可以试一试,机器卡死不负责! package com.itheima.jvm.demo; /** 栈内存溢出,注意!很危险,谨慎执行* 执行时可能会卡死系统。直到内存耗尽* */public class StackOutOfMem {    public static void main(String[] args) {        while (true) {            new Thread(() -> {                while(true);            }).start();        }    }} 1.3 本地方法栈1.3.1 概述本地方法栈的功能和特点类似于虚拟机栈,均具有线程隔离的特点 不同的是,本地方法栈服务的对象是JVM执行的native方法,而虚拟机栈服务的是JVM执行的java方法 虚拟机规范里对这块所用的语言、数据结构、没有强制规定,虚拟机可以自由实现它 甚至,hotspot把它和虚拟机栈合并成了1个 1.3.2 溢出异常
  和虚拟机栈一样,也是两个:
  如果是创建的栈的深度大于虚拟机允许的深度,抛出 StackOverFlowError
  内存申请不够的时候,抛出 OutOfMemoryError 1.4 堆1.4.1 概述
  与上面的3个不同,堆是所有线程共享的!所谓的线程安全不安全也是出自这里。
  在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java世界里"几乎"所有的对象实例都在这里分配内存。
  需要注意的是,《Java虚拟机规范》并没有对堆进行细致的划分,所以对于堆的讲解要基于具体的虚拟机,我们以使用最多的HotSpot虚拟机为例。
  Java堆是垃圾收集器管理的内存区域,因此它也被称作"GC堆",这就是我们做JVM调优的重点区域部分。 1.4.2 jdk1.7
  jvm的内存模型在1.7和1.8有较大的区别,虽然1.7目前使用的较少了,但是我们也是需要对1.7的内存模型有所了解,所以接下里,我们将先学习1.7再学习1.8的内存模型。
  Young 年轻区(代) Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区 其中,Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用 在Eden区间变满的时候, GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到下面的Tenured区间。 Tenured 年老区 Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。 Perm 永久区 hotspot 1.6 才有这货,现在已经成为历史 Perm代主要保存class,method,filed对象,这部份的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。另外一种可能是创建了大批量的jsp文件,造成类信息超出perm的上限而溢出。这种重启也解决不了。只能调大空间。 Virtual区: jvm参数可以设置一个范围,最大内存和初始内存的差值,就是Virtual区。 1.4.3 jdk1.8
  由上图可以看出,jdk1.8的内存模型是由2部分组成,年轻代 + 年老代。永久代被干掉,换成了Metaspace(元数据空间)
  年轻代:Eden + 2*Survivor (不变)
  年老代:OldGen (不变)
  元空间:原来的perm区 (重点!)
  需要特别说明的是:Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存空间中,这也是与1.7的永久代最大的区别所在。
  1.4.4 溢出异常
  内存不足时,抛出
  java.lang.OutOfMemoryError: Java heap space 1.4.5 案例:堆溢出
  1)代码
  分配大量对象,超出jvm规定的堆范围即可 package com.itheima.jvm.demo; import java.util.ArrayList;import java.util.List; /** * 堆溢出 *   -Xms20m -Xmx20m */public class HeapOOM {    Byte[] bytes = new Byte[1024*1024];    public static void main(String[] args) {        List list = new ArrayList();        int i = 0;        while (true) {            System.out.println(++i);            list.add(new HeapOOM());        }    }}
  2)启动
  注意启动时,指定一下堆的大小:
  2)输出 12345Exception in thread "main" java.lang.OutOfMemoryError: Java heap space	at com.itheima.jvm.demo.HeapOOM.(HeapOOM.java:7)	at com.itheima.jvm.demo.HeapOOM.main(HeapOOM.java:13)1.5 方法区1.5.1 概述
  同样,线程共享的。
  它主要用来存储类的信息、类里定义的常量、静态变量、编译器编译后的代码缓存。
  注意!方法区在虚拟机规范里这是一个逻辑概念,它具体放在那个区域里没有严格的规定。
  所以,hotspot 1.7 将它放在了堆的永久代里,1.8+单独开辟了一块叫metaspace来存放一部分内容(不是全部!定义的类对象在堆里)
  具体方法区主要存什么东西呢?粗略的分,可以划分为两类: 类信息:主要指类相关的版本、字段、方法、接口描述、引用等 运行时常量池:编译阶段生成的常量与符号引用、运行时加入的动态变量 (常量池里的类变量,如对象或字符串,比较特殊,1.6和1.8位置不同,下面会讲到)
  小提示:
  这里经常会跟上面堆里的永久代混为一谈,实际上这是两码事
  永久代是hotspot在1.7及之前才有的设计,1.8+,以及其他虚拟机并不存在这个东西。
  可以说,永久代是1.7的hotspot偷懒的结果,他在堆里划分了一块来实现方法区的功能,叫永久代。因为这样可以借助堆的垃圾回收来管理方法区的内存,而不用单独为方法区再去编写内存管理程序。懒惰!
  同时代的其他虚拟机,如J9,Jrockit等,没有这个概念。后来hotspot认识到,永久代来做这件事不是一个好主意。1.7已经从永久代拿走了一部分数据,直到1.8+彻底去掉了永久代,方法区大部分被移到了metaspace(再强调一下,不是全部!)
  结论:
  方法区是一定存在的,这是虚拟机规定的,但是是个逻辑概念,在哪里虚拟机自己去决定
  而永久代不一定存在(hotspot 1.7 才有),已成为历史 1.5.2 溢出异常
  1.6:OutOfMemoryError: PermGen space
  1.8:OutOfMemoryError: Metaspace 1.5.3 案例:1.6方法区溢出
  1)原理
  在1.6里,字符串常量是运行时常量池的一部分,也就是归属于方法区,放在了永久代里。
  所以1.6环境下,让方法区溢出,只需要可劲造往字符串常量池中造字符串即可,这里用到一个方法: /*如果字符串常量池里有这个字符串,直接返回引用,不再额外添加如果没有,加进去,返回新创建的引用*/String.intern()
  2)代码 /** * 方法区溢出,注意限制一下永久代的大小 * 编译的时候注意pom里的版本,要设置1.6,否则启动会有问题 * jdk1.6  :     -XX:PermSize=6M -XX:MaxPermSize=6M */public class ConstantOOM {     public static void main(String[] args) {        ConstantOOM oom = new ConstantOOM();        Set stringSet = new HashSet();        int i = 0;        while (true) {            System.out.println(++i);            stringSet.add(String.valueOf(i).intern());        }    }}
  3)创建启动环境
  4)异常信息: ...191181911919120Exception in thread "main" java.lang.OutOfMemoryError: PermGen space	at java.lang.String.intern(Native Method)	at com.itheima.jvm.demo.ConstantOOM.main(ConstantOOM.java:19)1.5.4 案例:1.8方法区溢出
  1)到了1.8,情况发生了变化
  可以测试一下,1.8下无论指定下面的哪个参数,常量池运行都不会溢出,会一直打印下去 -XX:PermSize=6M -XX:MaxPermSize=6M-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M
  2)配置运行环境
  3)控制台信息
  不会抛出异常,只要你jvm堆内存够,理论上可以一直打下去
  4)为什么呢?
  永久代我们加了限制,结果没意义,因为1.8里已经没有这货了
  元空间也加了限制,同样没意义,那说明字符串常量池它不在元空间里!
  那么,它在哪里呢?
  jdk1.8以后,字符串常量池被移到了堆空间,和其他对象一样,接受堆的控制。
  其他的运行时的类信息、基本数据类型等在元空间。
  我们可以验证一下,对上面的运行时参数再加一个堆上限限制: -Xms10m-Xmx10m
  运行环境如下:
  运行没多久,你会得到以下异常: ……840148401584016840178401884019Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded	at java.lang.Integer.toString(Integer.java:403)	at java.lang.String.valueOf(String.java:3099)	at com.itheima.jvm.demo.ConstantOOM.main(ConstantOOM.java:18)
  说明:1.8里,字符串inter()被放在了堆里,受最大堆空间的限制。
  5)那如何才能让元空间溢出呢?
  既然字符串常量池不在这里,那就换其他的。类的基本信息总在元空间吧?我们来试一下
  cglib是一个apache下的字节码库,它可以在运行时生成大量的对象,我们while循环同时限制metaspace试试:
  附:https://gitee.com/mirrors/cglib (想深入了解这个工具的猛击左边,这里不做过多讨论) package com.itheima.jvm.demo; import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * jdk8方法区溢出 *   -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M */public class ConstantOOM8 {    public static void main(final String[] args) {        while (true) {            Enhancer enhancer = new Enhancer();            enhancer.setSuperclass(OOM.class);            enhancer.setUseCache(false);            enhancer.setCallback(new MethodInterceptor() {                @Override                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {                    return methodProxy.invokeSuper(objects,args);                }            });            enhancer.create();        }    }     static class OOM{     }}
  6)运行设置
  7)运行结果 Caused by: java.lang.OutOfMemoryError: Metaspace	at java.lang.ClassLoader.defineClass1(Native Method)	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
  结论:
  jdk8引入元空间来存储方法区后,内存溢出的风险比历史版本小多了,但是在类超出控制的时候,依然会打爆方法区 1.6 一个案例
  为便于大家理解和记忆,下面我们用一个案例,把上面各个区串通起来。
  假设有个Bootstrap的类,执行main方法。在jvm里,它从class文件到跑起来,大致经过如下步骤:
  首先JVM会先将这个Bootstrap.class 信息加载到内存中的方法区 接着,主线程开辟一块内存空间,准备好程序计数器pc,虚拟机栈、本地方法栈 然后,JVM会在Heap堆上为Bootstrap.class 创建一个Bootstrap.class 的类实例 JVM开始执行main方法,这时在虚拟机栈里为main方法创建一个栈帧 main方法在执行的过程之中,调用了greeting方法,则JVM会为greeting方法再创建一个栈帧,推到虚拟机栈顶,在main的上面,每次只有一个栈帧处于活动状态,当前为greeting 当greeting方法运行完成后,则greeting方法出栈,当前活动帧指向main,方法继续往下运行 1.7 归纳总结
  1)独享/共享的角度: 独享:程序计数器、虚拟机栈、本地方法栈 共享:堆、方法区
  2)error的角度: 程序计数器:不会溢出,比较特殊,其他都会 两个栈:可能会发生两种溢出,一是深度超了,报StackOverflowError,空间不足:OutOfMemoryError 堆:只会在空间不足时,报OutOfMemoryError,会提示heapSpace 方法区:空间不足时,报OutOfMemoryError,提示不同,1.6是permspace,1.8是元空间,和它在什么地方有关
  3)归属: 计数器、虚拟机栈、本地方法栈:线程创建必须申请配套,真正的物理空间 堆:真正的物理空间,但是内部结构的划分有变动,1.6有永久代,1.8被干掉 方法区:最没归属感的一块,原因就是它是一个逻辑概念。1.6被放在了堆的永久代,1.8被拆分,一部分在元空间,一部分(方法区的运行时常量池里面的类对象,包括字符串常量,被设计放在了堆里) 直接内存:这块实际上不属于运行时数据区的一部分,而是直接操作物理内存。在nio操作里DirectByteBuffer类可以对native操作,避免流在堆内外的拷贝。我们下一步的调优不会涉及到它,了解即可。

outlookforwindowspre版体验既然咋用的是wind平台,总感觉他家的亲儿子才是最好的。因为有给outlook的邮箱,所以一直用系统自带的mail客户端,虽然功能不是很多但基本上能满足需求,而且是因为outloowireshark抓包教程详解如果本文对你有帮助,欢迎关注讨论点赞收藏转发给朋友,让我有持续创作的动力,让我们一起相互学习共同进步。Wireshark软件安装软件下载路径wireshark官网。按照系统版本选择独立分控互不影响断电,绿联新款四位分控延长线插座拆解前言绿联推出了多款新国标插线板,均配有安全门,高品质阻燃外壳和加粗线芯,并采用一体式铜条,具有更强的安全性,使用寿命更长,更加可靠。充电头网今天拆解的是一款四位分控插座,四个插孔均Linux内核进程调度器CPU负载目录背景概述全局CPU平均负载2。1基础概念2。2流程2。3计算方法运行队列CPU负载PELT4。1PELT计算方法4。2PELT计算调用背景Readthefuckingsourcoppo手机怎么投屏到电脑上?教你一个简单的投屏方法oppo手机怎么投屏到电脑上?如今投屏是很多手机都具备的功能之一,通过投屏功能我们在电脑上就可以看到手机上的内容了,这样会更加方便多人同时观看手机上的图片或是文档。但是每个手机的投比iPhone14Pro更强大!英国明年将推出革命性新手机?苹果iPhone14系列是首批支持SOS紧急联络功能的手机,即使在没有移动网络覆盖的地方发生意外,也可通过卫星传送定位及信息0资料,快捷地等待救援。不过iPhone14的SOS紧急300年,华为与苹果之间的距离,真的那么遥远?文丨侠说科技华为创始人任正非说,建立华为生态需要3年,赶上个苹果需要300年。这句话什么意思呢?我们以手机为例,国内智能手机行业中品牌林立,但若是给这些品牌排个名的话,苹果华为一定90后停用智能手机一年半反抗算法出门带手电筒等一堆工具摘要29岁的Leon决定停止使用智能手机。从2021年3月开始,这项试验已持续一年半。许多人好奇,没有智能手机,他怎么活下去呢?比如出行打车,扫健康码,以及如何即时回复工作信息等等C罗再遇危机!七成葡萄牙球迷反对他首发,场上一动作被主帅批评北京时间12月7日凌晨,卡塔尔世界杯最后一场18决赛即将打响,对阵双方是葡萄牙队和瑞士队。葡萄牙队在小组赛最后一轮12负于韩国队,但仍以小组第一的身份晋级淘汰赛。在那场比赛中,葡萄香港汇丰银行开户步骤是什么?具体有什么优势?香港汇丰银行是一家外资银行,全称是香港上海汇丰有限公司,是香港老品牌银行,也是香港金融管理局授权发钞银行之一,那么想要在香港汇丰银行开户步骤是什么呢,到底有哪些优势呢?香港汇丰银行购置税补贴将会延期?汽车股大涨或许另有原因最近几个交易日的A股,汽车整车板块成为了反攻主要进攻点。无论是资金流入还是板块活跃度,汽车整车表现出了非常强劲的活力。其实从疫情以来这三年,汽车整车板块的估值整体翻了三倍。原本资本
那些散落在人间的唯美句子你知道哪些很美的句子1。不管前方的路有多苦,只要走的方向正确,不管多么崎岖不平,都比站在原地更接近幸福。2。于千万人之中遇见你所要遇见的人,于千万年之中,时间的无涯的荒野里,没有早朋友圈走心的句子,简洁明了,人人点赞一世界上最难的事情,就是怎样成为一个人人都喜欢的人。二不要在乎谁离开了你,而是要关注你离开的时候谁在乎你。三热情这种东西,毕竟很脆弱,被忽略了几次后就再也提不起来了。四如果你给我的深度精辟人生哲理句子文案1与人结伴时不哗众取宠,独自生活时不顾影自怜。2我们改变不了常规的定律,但完全能掌控自己。3生活就是让弱者感觉无奈,让强者感觉无聊的游戏。4没有到不了的诗和远方,只有想走却不敢走的有感悟想笑的句子摘自网络,侵权请联系删除,谢谢好好好,小瑰同学啊。周主任苦口婆心,你这种啃老思想,或者考得好不如嫁得好的思想是错误的,现在已经是21世纪了,早就不流行那套男主外女主内了,作为我们女令人心痛到窒息的句子1我当时就想着,如果有人看见我这副在泥地里打滚,爬都爬不起来的样子以后,还能爱着我就好了,可我不确定有没有这样的人,我也不敢给别人看。2一直以为,你见过我最狼狈的样子以后还能继续爱那些看到就想要抄下来的句子(一百四十)假装谦虚是最虚伪的表现,因为这可能是信口雌黄的开始,又或者是拐弯抹角的自我夸奖。时间的维度被打破了,我们只能在时间的碎片中爱和思考,每一个时间的碎片沿着自己的轨迹运行,在瞬间消失。再信贾跃亭一次?FF公司官宣首款量产车FF91将于第四季度交付8月30日消息,法拉第未来(简称FF)发布业务进展更新,融资活动和推出首款量产车FF91电动车正在同步进行,重申新车将于2022年第四季度开始量产交付。据FF公司称,位于美国加州汉网传多家应用软件公司遭受勒索病毒攻击,畅捷通金蝶等回应钛媒体App8月30日消息,近日,有消息称多家应用软件公司部分遭受勒索病毒攻击,对此畅捷通金蝶等先后发表声明。畅捷通声明中称,对于网传少量T软件客户也反馈受到勒索病毒攻击的说法,核言情小说(年轻漂亮的小美妇)第一百二十一章身板消瘦的沈丽在田里打着农药,着实让人心疼,虽然在农村晒黑了些,但是也掩盖不了那超高颜值的脸。狗胜看着那么辛苦的沈丽,赶忙加快脚步走了过去,铜锤和大嘴紧跟在狗胜身后。你们看这三个丑现代年轻人常见的几种坏习惯,你占了几种?现在很多的年轻人,他们仗着自己年轻,不爱惜身体,不断挥霍自己的健康,直到感觉出现身体不适之后,才回过神来用保温杯泡枸杞养生,大部分年轻人都有的几种坏习惯,这些坏习惯等于慢性自杀,看上半年旅游业有多惨?11家景点上市公司全部亏损,日亏428万元今年上半年,国内疫情持续反复多点散发,大部分省份实施跨省游熔断机制,疫情防控政策收紧,游客出行受限,节假日旅游出游人次同比下降,国内旅游业持续承压。受其影响,旅游业上市公司的财报也