Java虚拟机从入坑到入土
Posted Java从入坑到入土
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java虚拟机从入坑到入土相关的知识,希望对你有一定的参考价值。
今天来了解一下Java的内存区域分为哪些部分及各个部分的功能特点,本文的所有知识均由笔者从《深入理解Java虚拟机》归纳及总结,若有任何理解不恰当的地方,欢迎大家向我提出!非常乐意与你们交流!
首先我们来看看Java的运行时数据区域
也许第一次看到这幅图的时候,我们都会有一种感觉就是很乱,不知道是什么东西,我们可以将运行时数据区里面的五大区域分成两大部分:
一、线程共享
所有线程都会共享这些区域,线程的相关操作都会对其它线程可见并有可能带来影响。
1. 堆
堆的作用是
存储对象实例
,也就是我们最常见的使用对象时,必须要先new一个对象它是
内存最大
的一块区域它是
垃圾回收器的主要区域
:Java和C++的区别就好比吃完饭以后,如果我们要自己把垃圾扔到垃圾桶里面,那么就是C++;而如果我们吃完饭不用主动扔垃圾,垃圾会被其他打扫卫生的清洁人员回收,那么这就是Java的特性,不用自己去回收垃圾。而交给垃圾回收器去回收。(了解)Java堆可细分为新生代和老年代、Eden空间、Survivor空间······这些都是为了方便垃圾回收器识别各种不同的对象的特性,提高回收垃圾的效率,但是各个空间都是存储对象实例,没有任何存储内容上的区别。
当堆中的内存被使用完并且无法再扩展时,就会抛出
OutOfMemoryError
异常。
2. 方法区(近乎于"永久代")
方法区的作用是存储已经被JVM加载的信息:类信息、常量、静态变量、即时编译器编译后的代码、常量池
方法区可选择不实现垃圾回收,因为大部分数据进入方法区就是
"永久"
存在的了;方法区进行垃圾回收的目标主要是常量池的回收及类型的卸载当方法区无法满足内存分配需求时会抛出
OutOfMemoryError
异常
2.1 运行时常量池
它是方法区的其中一部分,具备动态性:在运行期间能够将新的常量放入池中,典型的例子是:
String.intern()
当它无法向方法区申请到内存时会抛出
OutOfMemoryError
异常
二、线程私有
每个线程创建时都会有自己独立的区域、线程之间不互相共享这些区域!
1. 程序计数器
调用
native
方法时程序计数器不工作,指向空
native
方法指的是在Java中可调用的方法,但是方法体不是由Java代码编写的,有可能是由C或C++编写的由于不是由Java语言编写的方法,自然也无法生成字节码,并且C/C++方法执行时的内存分配是由其语言本身决定的,不能由JVM决定。
程序计数器是唯一一个不会抛出异常的区域,因为其占用的内存非常的小,可忽略不计
2. Java虚拟机栈
执行Java方法,每个方法在执行时都会创建栈帧,方法执行结束后,栈帧会弹出虚拟机栈,相信大家会对这句话有点印象,在初学Java时会听说过方法压栈执行和结束弹栈这两个概念。
栈帧是方法运行的基本数据结构,它主要含有局部变量表、操作数栈、动态链接、方法出口······
局部变量表在编译期完成内存分配,也就是说在栈帧中局部变量表需要多少内存空间是完全确定的,不会在程序运行时改变。
当线程请求的栈帧深度大于Java虚拟机栈的深度时,无法继续放入栈帧,此时会抛出
StackOverFlow异常
常见情况:死递归(晕乎乎~)
当虚拟机栈请求的内存空间大于主机内存时,会抛出
OutOfMemoryError
异常,虚拟机栈内存不可能大于主机内存!
returnAddress
类型个人理解:
我认为这也就是为什么在执行返回值为void
类型的方法时也可以手动添加return ;
去提前终止方法的原因。
3. 本地方法栈
执行
native
方法,什么是native
方法在上面有介绍它和Java虚拟机栈的作用几乎是一样的
为什么将本地方法栈和Java虚拟机栈不合二为一呢?
在著名的
Sun HotSpot
虚拟机中就是将它们合二为一了,具体细节没有深究,有兴趣的读者可以去了解了解。它同样也会抛出与Java虚拟机栈相同的两个异常
三、结尾
感谢你们阅读我编写的推文!今天就介绍这么多啦,希望能让你们对于JVM的运行时数据区域有一个初步的了解,起码你会了解到JVM会分为哪几个区域,它们各自的功能是什么,尽管这都是一些基础性的概念知识,但是我认为基础的知识也是非常重要的,如果我有任何写得不正确和不准确的地方,欢迎大家向我提出来,我们可以一起学习和交流!
2019年9月20日
小菠萝 以上是关于Java虚拟机从入坑到入土的主要内容,如果未能解决你的问题,请参考以下文章 Flutter开发之dart语言从入门到精通(从入坑到入土) Flutter开发之dart语言从入门到精通(从入坑到入土)