前言
这篇文章对应系列(二)而诞生,什么不会学什么。当初在学习的时候其实只是想有个线性的学习过程,但是书籍是做了系统的分模块介绍,并没有给我循序渐进的感觉。而且有时候与实际并没有太多的联系,很多环节不去想就不会对应了(但是还挺有趣)
根据Java虚拟机规范,定义了内存区域
0x01 程序计数器
线程私有(所以生命周期随线程而生死)
作用:线程从中获取所需要执行的字节码的行号指示器,如果执行的是本地方法栈方法则为null
异常:Java虚拟机规范没有规定任何OutOfMemoryError
0x02 Java虚拟机栈
线程私有
作用:描述java方法执行的内存模型,每个方法在执行时才会创建一个栈帧
所以一些方法需要的信息都会在栈帧中,一些参数也会在其中
异常:线程请求栈深度大于虚拟机允许的深度,抛出StackOverflowError,虚拟机栈可以动态扩展,如果扩展无法申请足够多的内存,抛出OutOfMemeoryError
0x03 本地方法栈
非线程私有
作用:类似Java虚拟机栈,提供本地的Native方法
异常:同Java虚拟机栈
0x04 Java堆
非线程私有
作用:存放对象实例的地方(大部分,但是随着逃逸分析技术、栈上分配、标量替换等新技术出现,也不是所有对象都在堆上分配)
异常:若没有内存分配对象实例,抛出OutOfMemeoryError
jvm参数:-Xmx最大值和-Xms最小值
根据垃圾收集算法,java堆还可以细分到Eden区和Survivor区,都是为了垃圾回收
0x05 方法区
非线程私有
作用:存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
异常:抛出OutOfMemoryError异常
ps1:hotspot将其作为永久代,目的是为了将其与新生代、老年代一起做垃圾回收,可以理解为垃圾回收延长到了方法区(因为hotspot用永久代了实现方法区)
ps2:作为永久代来说,很容易遇到内存溢出问题,因为有少数方法在不同虚拟机下可能会用到永久代,所以可能导致内存溢出。比如String的intern方法
0x06 运行时常量池
非线程私有
作用:方法区的一部分,用于存放编译期生成的各种字面量和符号引用,具有动态性,程序运行期间也有可能将新变量放入常量池
异常:抛出OutOfMemoryError异常,受到方法区内存大小的限制
0x07 直接内存
非虚拟机运行时数据区的一部分
作用:nio有使用到
异常:抛出OutOfMemoryError异常
0xFF 总结
Java程序在启动的时候要分配线程去执行代码,那么这个时候这个线程拥有自己的内存空间(程序计数器、java虚拟机栈),然后会操作java堆中的内存(堆内存共享,所以多个人去搞同一个地方的东西是不是可能会出问题?当然终极原因还是因为硬件级别的问题)
这些内存空间只是为了存放程序运行时数据,而这些数据也不是一直存在的。所以为了方便回收这些不需要的数据(垃圾)才进行这些内存结构的划分