原创 | jvm01、JVM内存结构
庆哥有话说
java内存结构也就是jvm内存结构,我们经常说的是jvm内存结构,包含了堆内存,栈和方法区等内容,是学习jvm必备的知识,所以jvm内存结构这块知识的学习是很重要的!
首先要知道的就是java内存结构等同于jvm内存结构!下面是jvm的内存结构图
然后jvm内存结构包含以下内容:
- 程序计数器
- java虚拟机栈
- 本地方法栈
- java堆
- 方法区运行时常量池
因此,学习jvm的内存结构也就是要弄懂上面几个东西!
小白带你快速了解
程序计数器
较小的内存空间,可以当成是当前线程执行的字节码的行号指示器,也就是根据这个程序计数器来决定下一步要执行啥!线程私有!
java虚拟机栈
这个就是咱们经常说的栈内存,准确来说是java虚拟机栈中的局部变量表。存放基本数据类型和对象引用,注意是局部变量表,java虚拟机栈中存放的可不止这些!线程私有,与java方法相关,生命周期同线程一样!
本地方法栈
与java虚拟机栈非常相似,有的虚拟机就把本地方法栈和java虚拟机栈合二为一,比如Sun HotSpot虚拟机!
堆
这个就是堆内存了,应该算是jvm内存中大家接触的最多的一个,它是jvm内存中空间最大的一块内存,主要存储对象实例。也是gc主要光顾的地方。
方法区和运行时常量池
和java堆一样,是线程共享的,存储被虚拟机加载的类信息,常量,静态变量,即时编译后的代码等数据,字符串常量池在jdk1.7之前在方法区,在jdk1.7及之后字符串常量池从方法区移除,放在了堆内存中。
运行时常量池也在方法区中,用于存放Class文件中的字段,方法,接口和常量池等信息内容。
庆哥陪你深入分析
程序计数器
程序计数器,有的地方也叫作pc计数器,都是它,是在jvm内存中属于较小的额一个内存空间,但是十分重要,我们知道在多线程中,是靠CPU来切换线程的执行顺序的方式实现的,也就是说,从线程A切换到线程B,然后再切换到线程A的时候,你有没有想过cpu是怎么知道应该执行线程A中的哪一步,也就是说,之前在线程A中执行到哪了,这就要靠程序计数器去记录了。
这就是程序计数器了,另外要知道的就是程序计数器是线程私有的,互相独立,如果被问到什么是程序计数器,我觉得可以这样回答:
当前线程所执行的的字节码的行号指示器!
java虚拟机栈
我们之前应该经常会说或者经常听到堆内存和栈内存,堆内存想必大家都很熟悉了,这个我们随堆内存经常说的栈内存准确的来说应该是java虚拟机栈中的局部变量表,在此之前我们应该也知道一个常识就是基本数据类型是存放在栈内存中的,对象是存放在堆内存的,现在准确的去说,基本数据类型是存放在java虚拟机栈中的局部变量表中的。
java虚拟机栈也是线程私有的,生命周期跟随线程,很重要的一个点就是要明白java虚拟机栈是与java方法相关的,什么意思呢?
当线程开始,也就产生了这个java虚拟机栈,当一个java方法会调用的时候就会产生一个栈帧,这个栈帧是用来干嘛的呢?
这个时候产生的一个栈帧就是用来存放局部变量表,操作数栈,动态链接和方法出口信息等,注意了,这里的局部变量表是在栈帧中保存。另外,一个方法从调用到执行结束的整个过程就是一个栈帧在java虚拟机栈中从入栈到出栈,这就把栈帧和java虚拟机栈联系起来了。
而这个局部变量表是干嘛的呢?就是用来存放各种基本数据类型,对象的引用得,想必这个大家都熟悉,就是大家常说的栈内存所做的事情啊。可能这里还要注意的就是这里说的基本数据类型都是在编译期就已经确定下来的,而且局部变量的的空间在编译期就是确定的,运行时期是不会再改变的。
本地方法栈
想必这个一定会让大家想到java虚拟机栈,那么两者有什么区别呢?其实极为相似,不同的是服务的对象不同,java虚拟机栈是为执行java方法服务,而本地方法栈是为使用到的Native方法服务,那么重点来了,什么是Native方法呢?
关于native方法我这里简单说下我的理解,java号称吸收了c加加和c语言的优点,剔除了较难的指针,不过,我是学java的,我就认为java好,可是嘞,不得不承认,java语言要比c++的运行慢很多,另外也是因为没有指针吧,所以java并不能去直接操作底层,为了弥补这个缺点,也就有了native方法,来建立这么一种联系。
关于native方法,就说这么多,大家可以自行搜索学习,等我研究的差不多了再来分享!
堆
堆内存是我们要经常与之打交道的一块内存地址,所有的实例对象和数组都在这里存储,也是垃圾回收器主要工作的地方,所以堆内存也叫作gc堆,也就是垃圾堆,哈哈。
当然可能大家也知道,在堆内存中其实也是有划分的,比如分有新生代和老年代,再细致一点的话有Eden空间,from和to空间等,我们这里要把握的是无论怎么划分,存放的就是对象实例就ok了。
对java堆中我们后面会单独拿出来说的,因为很重要!还需要记住的是堆内存是所有线程共享的。
方法区和运行时常量池
这块知识我们需要掌握的一个重点就是在jdk1.7之前字符常量池是存放在方法区中的,但是在jdk1.7及之后就从方法区中移除了字符串常量池,放在了堆中。
方法区也是多个线程共享的,存放已经被虚拟机加载的类信息,常量和静态变量等数据信息,在方法区中还存在一个运行时常量池,这个是值得好好研究的。
首先是Class文件中除了有类的字段,方法和接口等描述信息之外还有一个常量池,这些内容会在类加载后进入方法区的运行时常量池。
而这个常量池是用于存放编译阶段生成的各种字面量和符号引用
声明:文章参考《深入理解java虚拟机》一书!