JVM内存模型(JMM)

返回目录
全称是Java Memory Model。JMM关键技术点都是围绕着多线程的原子性、可见性、有序性来建立的。
在这里插入图片描述

原子性

原子性是指操作是不可分的,要么全部一起执行,要么不执行

可见性

可见性是指一个线程对共享变量的修改,对于另一个线程来说是否是可以看到的。
Volatile关键字可以使工作内存中的数据更新到主内存,这样,在其他线程使用此数据时不会造成脏数据

有序性

有序性指的是程序按照代码的先后顺序执行。

JMM抽象模型分为主内存、工作内存

主内存是所有线程共享的,一般是实例对象、静态字段、数组对象等存储在堆内存中的变量。
工作内存是每个线程独占的,线程对变量的所有操作都必须在工作内存中进行,不能直接读写主内存中的变量,线程之间的共享变量值的传递都是基于主内存来完成。

JMM是如何解决可见性有序性问题的

简单来说,JMM通过使用内存屏障,提供了一些禁用缓存以及禁止重排序的方法,来解决可见性和有序性问题。这些方法大家都很熟悉:volatile、synchronized、final;
在这里插入图片描述

JVM内存结构

在这里插入图片描述
包括:
• 程序计数器(PC)
• java虚拟机栈
• 本地方法栈
• java堆
• 方法区
在这里插入图片描述

方法区(MethodArea)也称"永久代“

方法区是被所有线程共享的内存区域,用来存储已被虚拟机加载的类信息、常量、静态变量、JTI(just in time,即时编译技术)编译后的代码等数据。
运行时常量池是方法区的一部分,用于存放编译期间生成的各种字面常量和符号引用。
当存放方法区数据的内存溢出时,会报OutOfMemoryError异常,在jdk1.8中也就是Metaspace内存溢出。
可以通过参数JVM参数-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置Metaspace的空间大小。
随着JDK8的到来,JVM不再有 永久代(PermGen)。但类的元数据信息(metadata)还在,只不过不再是存储在连续的堆空间上,而是移动到叫做“Metaspace”的本地内存(Native memory)。

java堆(Heap)

java堆是被所有线程共享的内存区域,也是jvm管理的最大一块内存,几乎所有的对象实例都在heap中分配。

程序计数器

程序计数器是线程独享的,指向当前线程正在执行的字节码指定的地址。

虚拟机栈

虚拟机栈是线程独享的,存储每个线程中运行的各个方法所需要的数据、指令、返回地址等信息,用于描述java方法执行的内存模型。
-Xss用于指定栈的深度(栈帧的个数),如果栈深度太深,则会报异常StackOverFlowException

本地方法栈

本地方法栈与虚拟机栈类似,区别在于虚拟机栈执行的是java方法,而本地方法栈则为执行虚拟机中的native本地方法。
JVM优化
在这里插入图片描述
在这里插入图片描述

Eden : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 )

• -Xms设置堆的最小空间大小。
• -Xmx设置堆的最大空间大小。
• -Xmn:设置年轻代大小
• -XX:NewSize设置新生代最小空间大小。
• -XX:MaxNewSize设置新生代最大空间大小。
• -XX:PermSize设置永久代最小空间大小。
• -XX:MaxPermSize设置永久代最大空间大小。
• -Xss设置每个线程的堆栈大小
• -XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
• -XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。

常量池

Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。

静态常量池:

主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:
类和接口的全限定名
字段名称和描述符
方法名称和描述符

运行时常量池

是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

常量池的好处

常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
(2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值