JAVA内存模型
线程角度
程序计数器(Program Counter Register)
当前程序所执行的字节码行号指示器(逻辑)
改变计数器的值来选取下一条需要执行的字节码指令
和线程是一对一的关系即“线程私有”,一个明确的时间点,处理器只会执行一个线程的代码,就需要其他线程存储自己的程序计数器,以便处理器在切换线程的时候,可以继续执行上次未执行完的逻辑。
对java方法计数,如果正在执行的方法是native方法则计数器值为undefined
因为只是记录行号,程序计数器不必担心内存泄漏的问题
JAVA虚拟机栈(Stack)
JAVA方法执行的内存模型
包含多个栈帧
局部变量表和操作数栈
局部变量表:包含方法执行过程中的所有变量
操作数栈:入栈、出栈、复制、交换、产生消费变量。栈模型,先进后出,当方法中调用其他方法,那么也是后调用的方法先执行完,才会执行外层的方法,这就符合了栈模型。
递归为什么会引发java.lang.StackOverflowError异常?
虚拟机栈过多会引发java.lang.OutOfMemoryError异常
本地方法栈
与虚拟机相似,主要作用于标准了native的方法。
元空间(MetaSpace)与永久代(PermGen)的区别
元空间直接使用本地内存,而永久代使用JVM内存。好处:本地内存剩余多少,元空间就有多大,元空间的数据不再占用JVM内存。也不会放任元空间无限大,JVM在启动的时候会去设置元空间内存大小。
元空间相比永久代的优势
字符串常量池存在于永久代中,容易出现性能问题和内存溢出。
类和方法的信息大小难以确定,给永久代的内存大小指定带来困难,太小容易出现永久代内存溢出,太大导致内存浪费
永久代会给GC带来不必要的复杂性
方便hotSpot与其他JVM如jrockit集成
JAVA堆(Heap)
对象实例的分配区域
JVM三大性能调优参数-Xms -Xmx -Xss的含义
java -Xms128m -Xmx128m -Xss256k -jar xxxx.jar
-Xss:规定了每个线程虚拟栈(堆栈)的大小,此配置将会影响此JVM中线程并发数的大小
-Xms:堆的初始容量大小,一旦对象容量超过堆的初始容量,堆将会扩容
-Xmx:堆扩容后的大小,能达到的最大值
在很多情况下,我们通常将-Xms和-Xmx设置成一样的,因为当堆不够用进行扩容时,会发生内存抖动,影响程序的稳定性。
JAVA内存模型中内存分配策略
静态存储:编译时确定每个存储目标在运行时的存储空间需求。要求程序代码中,不允许有可变数据结构的存在,也不允许有嵌套和递归的结构出现,以为它们都会导致程序在编译时无法确定空间的存在。
栈式存储:数据区需求在编译时未知,运行时模块入口前确定。在进入一个程序模块的时候,必须知道进入该模块的数据区大小,才能分配其内存。
堆式存储:编译时或运行时模块入口都无法确定,动态分配。
JAVA内存模型中堆和栈的区别
栈和堆的联系:引用对象、数组时,栈里定义的变量实际上保存的是数据在堆中的地址,就可以使用栈中的引用变量,来访问堆中的数据。堆中的数据在没有被任何栈中变量引用的时候,才可能随后被GC回收释放掉。
管理方式:栈自动释放,堆需要GC
空进大小:栈空间比较小,堆空间一般都比较大,因为要存储JAVA对象数据
碎片相关:栈产生的碎片远小于堆
分配方式:栈支持静态分配和动态分配,而堆仅支持动态分配,静态分配是本身由编译器分配好了,动态分配可能根据情况有所不同。而堆空间只能动态。
效率:栈的效率比堆高,因为栈的释放JVM就可以控制,而堆需要靠GC,GC又不是实时的。
来源:oschina
链接:https://my.oschina.net/xiaoyoung/blog/4314584