本文已参与「新人创作礼」活动,一起开启掘金创作之路。
JMM目标是屏蔽各种硬件和操作系统之间的内存访问差别,而让JAVA程序在各种平台对内存的拜访统一。
JMM规定所有的变量都存储在主存中,每个线程都有独立的工作内存,线程对变量的操作必须先从主存中读取到工作内存中再进行操作,操作完后再回写到主存。
JMM只是一种模型,具体的实现可能和模型有差别。JMM和JVM不一样,并不是同一个档次的划分。
简述JVM内存模型
线程私有的运行时数据区: 程序计数器、 虚拟机栈、本地方法栈。
线程共享的运行时数据区: 堆、方法区。
简述程序计数器
程序计数器是记录当前线程执行的字节码的行号指示器。
不会产生StackOverflowError和OutOfMemoryError。无GC
简述虚拟机栈
虚拟机栈是Java方法执行的内存模型。
线程创建时会分配一个栈空间,每个方法执行时会在栈中创建一个栈帧,存储方法的局部变量表、操作栈、返回地址等信息,线程结束后栈空间被回收。
虚拟机栈会产生两类异常:
StackOverflowError:线程请求的栈深度大于虚拟机允许的深度时抛出。
OutOfMemoryError:若栈容量可以动态扩展,虚拟机栈占用内存超出限制时抛出。无GC
简述本地方法栈
本地方法栈与虚拟机栈作用相似,不同在于:
虚拟机栈是普通java函数对应的内存模型,为执行Java 方法服务。
本地方法栈是native关键字修饰的函数对应的内存模型,为执行本地方法服务。
本地方法栈会产生两类异常:
StackOverflowError:线程请求的栈深度大于虚拟机允许的深度抛出。
OutOfMemoryError:如果栈容量可以动态扩展,虚拟机栈占用内存超出限制抛出。无GC
简述JVM中的堆
堆主要用于存放对象实例,Java中几乎所有对象实例都在堆分配内存。Java的垃圾回收主要针对堆区域进行
可通过 -Xms设置初始堆大小 和 -Xmx 设置堆的大小上限。
堆会抛出 OutOfMemoryError异常。有GC。方法区有(有Full GC,加载jar包过多)OOM
堆外内存:直接内存、栈内分配空间
直接内存也称为堆外内存,是把对象分配在JVM堆外的由操作系统来管理的内存区域。
Java通过可用DriectByteBuffer对其进行操作。
优点:在数据远程发送时,需要把java堆内的数据复制到堆外内存才能发送,直接使用堆外内存分配对象则避免了在 Java 堆和 Native堆复制数据的过程。还可以减少GC垃圾回收的负担。
缺点:没有jvm管理内存,若一直没有FLL GC进行垃圾回收,则可能产生内存溢出。
逃逸分析
什么是逃逸分析?
逃逸分析,是跨函数全局数据流分析算法。可以有效减少程序中同步负载和内存堆分配压力。通过逃逸分析,编译器能够分析出一个新的对象的引用的使用范围,从而使用栈上分配、锁消除(同步省略)、分离对象等优化策略.
逃逸分析的原理?
Java本身的限制(对象只能分配到堆中),为了减少临时对象在堆内分配的数量,在一个方法体内定义一个局部变量,并且该变量在方法执行过程中未发生逃逸,按照JVM调优机制,首先会在堆内存创建类的实例,然后将此对象的引用压入调用栈,继续执行,这是JVM优化前的方式。然后,我采用逃逸分析对JVM进行优化。即针对栈的重新分配方式,首先找出未逃逸的变量,将该变量直接存到栈里,无需进入堆,分配完成后,继续调用栈内执行,最后线程执行结束,栈空间被回收,局部变量也被回收了。如此操作,是优化前在堆中,优化后在栈中,从而减少了堆中对象的分配和销毁,从而优化性能。
基于逃逸分析的代码优化策略