JVM内存结构

内存结构图


下面一一介绍下:

程序计数器

程序计数器用于记录cpu下一条需要执行的指令的地址,帮助执行引擎完成对数据的加载,运算等工作。
在这里插入图片描述
程序计数器是线程私有的,生命周期与线程的生命周期保持一致。
为什么被设定为私有的呢?
为了能够准确地记录各个线程正在执行的当前字节码指令地址,最好的办法自然是为每一个线程都分配一个程序计数器,这样一来各个线程之间便可以进行独立计算,从而避免cpu频繁的进行上下文切换。

每个线程在创建的时候都会创建一个「虚拟机栈」,每次方法调用都会创建一个「栈帧」。调用方法时栈帧入栈,调用结束方法出栈、

每个「栈帧」会包含几块内容:参数,局部变量、方法的返回地址等

栈是线程私有的,所以栈的生命周期和线程一致,当线程结束了,该虚拟机栈也就销毁了。

和堆对比
栈是线程私有,堆是线程共享
栈是运行时的单位,而堆是存储的单位
栈解决程序的运行问题,即程序如何执行,如何处理数据。
堆解决的是数据存储的问题,即数据怎么放,放哪里

栈溢出
栈不存在垃圾回收问题,因为出栈即相当于回收,但是存在栈溢出的情况,比如递归爆栈

更多

本地方法栈

本地方法栈跟虚拟机栈的功能类似:
虚拟机栈用于管理 Java 函数的调用
而本地方法栈则用于管理本地方法的调用。这里的「本地方法」指的是「非Java方法」,一般本地方法是使用C语言实现的。

1、堆内存细分
堆空间分为:新生区+养老区+元空间
新生区又被划分为Eden区、Survivor1区和Survivor2区
默认大小占比如下:

新生代:老年代  - >  1 : 2
Eden:From:to ->  8:1:1

所有的Java对象都是在Eden区产生的
并且绝大部分的Java对象在新生代就销毁了,不会进入老年代
在这里插入图片描述

2 、堆是线程共享的
但是,堆空间也并非全部都是共享的,因为在堆中还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB)

3、《Java虚拟机规范》中对Java堆的描述是:所有的对象实例以及数组都应当在运行时分配在堆上,注意这里是应当不是一定
所以实际是:大部分对象分配在堆上。一小部分没有发生栈上逃逸的会在栈上分配
这点和c++不一样,c++是用new创建的对象放堆上,不用new的放栈上

4、默认生命周期为15,超过15进入老年代
为什么是15呢?
因为标识分代年龄的空间大小是4bit,最多记录到15.

5、堆内存大小
“-Xms"用于表示堆区的起始内存
“-Xmx"则用于表示堆区的最大内存
通常会将起始内存和最大内存配置成相同的值,一开始就把最大的给你,别老是找我要了
一旦堆区中的内存大小超过“-xmx"所指定的最大内存时,将会抛出OOM异常。

6、垃圾回收的频率
频繁在新生区收集,很少在老年代收集,几乎不再永久代|元空间进行收集

更多

方法区

首先明确:只有Hotspot才有方法区的概念。其他虚拟机是不存在这一概念的。

方法区是规范,是逻辑概念,原则上如何实现方法区属于虚拟机实现细节,不受《Java虚拟机规范》管束,并不要求统一。
所以永久代和元空间都是HotSpot实现方法区这一概念的方式。

  • Java8之前的版本,用永久代实现方法区;
  • Java8之后的版本,用元空间实现方法区;

元空间与永久代最大的区别在于:
永久代在堆内存中,元空间在堆外

JVM在1.8时用元空间代替永久代的原因
随着Web领域的发展,Java程序变得越来越大,需要加载的内容也越来越多,永久代是放在堆内存中的,占用的是堆内存空间,所以容易OOM
而元空间放在本地内存中,使用元空间之后,就可以将数据直接存储在本地内存当中,减少了OOM的可能性。

添加链接描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值