java jvm 内存模型_JAVA-JVM 基于JDK1.8 内存模型

首先说一下JVM JRE 的一部分,也是java程序最基础的部分,缺了java程序就无法运行,

Java 程序能够跨平台运行完全是因为java对不同的操作系统提供了不同的JVM。

计算机运行的无非就是:指令+数据。指令用来执行方法,数据用于存放数据和对象。

1) JVM  的执行过程:

70c71dc8ac443428ba93985535270f33.png

2)运行时数据区就是我们平时所说的JVM内存模型:JMM

JVM在运行过程中会把它所管理的内存划分成若干不同的数据区域!

1 线程私有:程序计数器、虚拟机栈、本地方法栈 。(Java每开启一个线程就开辟这几块区域,每个线程都是互不干扰的。),随着线程的结束而消失。

2 线程共享:堆、方法区 。

98eaea5921a351c49684fe9ce8f83bd1.png

程序计数器:唯一不会发生内存溢出的区域(OOM),指向当前线程正在执行的字节码指令地址行号。

(JAVA是多线程的,意味着线程切换;确保多线程情况下程序能正常运行。)

栈:是一种数据结构,FILO,先进后出。(为什么使用栈:兼容方法的嵌套调用,以及程序调用方式,方法都是后面调用的值返回到当前地方继续执行,个人觉得)

本地方法栈:本地方法栈保存的是native方法的信息,当一个JVM创建线程调用native方法后,JVM不再为其在虚拟机栈中创建栈帧(普通一个方法一个栈帧,不再分配内存给本地方法),而是简单的动态链接并直接调用。( 首先说一下本地方法是指由native修饰的方法,一般是用来调用底层操作系统的。)

虚拟机栈:私有模型中,重点关注部分,大小(每个线程)设置(-Xss 1 M 默认大小),虚拟机栈总大小无法设定,因为每个线程都会分配一个块私有内存区域(包含虚拟机栈,本地方法栈,程序计数器);存储当前线程运行需要的数据、指令、返回地址。虚拟机栈会为运行到的每个方法开辟一块栈帧(包含:局部变量表,操作数栈,动态链接,方法出口(返回值)等),(除本地方法之外,本地方法用的是动态链接直接调用方式),当前线程执行的方法就在虚拟机栈的栈顶。局部变量表会持有new 出来对象的引用。

2c1b3387536906e88045cd1ff1f208d3.png

堆:(-Xms;-Xmx;-Xmn) (最小,最大,新生代),JAVA内存模型中,重要关注部分,因为涉及到了内存分配(new    关键字,反射等)与回收算法,收集器等。几乎所有的对象(实例变量(在类中没有final、static修饰的变量),new)都在堆中。

方法区:(永久代(jdk1.7以前)、元空间(jdk1.8))存放 类信息、常量(final) 、静态变量、即时编译后的代码。

3)JVM各版本内存区域的变化

运行时常量池  :Class 文件中的常量池(编译器生成的各种字面量和符号引用)会在类加载后被放入这个区域。

符号引用,    字面量:String a =“你好”,八种基本类型 int a=1;这个1 就是字面量,声明为final的常量

例子:String a ="ab";  编译的时候确定不了a的值,所以“ab”是运行时动态加载到常量池的;

final String b ="cd"; final 修饰编译的时候就会把“cd”加载到常量池。

而且字面量加载到常量池与final,static 修饰无关。

3ba524315512d6632e30dcb4441e1ca1.png

JDK1.6     运行时常量池在方法区中

JDK1.7      运行时常量池在堆中

实验证明JDK1.8的常量池在堆中,而方法区只是存了常量的引用:

如下两个图可以证明运行的常量池是在堆中,而方法区中只是存了常量的符合引用,所以前后变化不大。

c869cdf5859db7a3e69c7292e248bfc7.png

316ff6db8b9ae4abdcc3e78e979c4ae4.png

JDK1.8     去永久代:使用元空间(空间大小只受制于机器的内存)替代永久代

永久代参数    -XX:PermSize;-XX:MaxPermSize =100M   超过100M         OOM()

元空间参数    -XX:MetaspaceSize; -XX:MaxMetaspaceSize

永久代是用来存储类信息、常量、静态变量、等数据不是个好主意,很容易发生内存溢出的问题。

对永久代进行调优是很困难的,同时将元空间与堆的垃圾回收进行隔离,避免了永久打引发FullGC和OOM等问题。

jdk1.7以前永久代的内存分配机制和垃圾回收机制跟堆策略基本是一样的,这样管理起来非常麻烦,所以jdk1.8之后就去永久打,方法区就用了元空间,这样方法区就与与堆隔离了。

4)直接内存:JVM规范里面没有规定的区域。

e3d8aee68fa754cbfa309e802fa4f795.png

直接内存不是虚拟机运行时数据区的一部分,也不是java虚拟机中规范定义的内存区域。

如果使用了NIO,这块区域会被频繁使用,在java堆内可以用directByteBuffer对象直接引用并操作(零拷贝的应用);

这块内存不受java堆大小的限制,但受本机总内存的限制,可以通过MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常。

避免了在Java 堆和Native 堆中来回复制数据,能够提高效率。

0daf2adcb29c49f94d6b8768dba4b107.png

5)站在线程的角度

0dc1c86b63179106634476dc92630fe2.png

6)深入理解栈和堆

a7a8d18af2adc585528d77637a068438.png

7)未来的JAVA 技术

模块化:OSGI(动态化、模块化),应用层面就是微服务,互联网发展的方向。

混合语言:多个语言都可以运行在JVM中,google的Kolin成为了Android的官方语言。Scala(Kafka)

多核并行:CPU从高频次转为多核心,多核时代。JDK1.7引入了Fork/Join,JDK1.8提出了lamba表达式(函数式编程天生合适并行运行)。

8)整体JDK1.8 JVM 内存模型图

cc7f774016c7d9e12420a52b9fc9fd23.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值