JVM基础

JVM运行时数据区

JVM运行时数据区由以下组成:

  • 程序计数器:指向当前线程正在执行的字节码指令的地址行号等。(记录程序运行到哪里了),每条线程都有一个独立的程序计数器。此区域JAVA虚拟机规范没有规定任务OutOfMemoryError异常
  • 虚拟机栈:用于存储局部变量表(基本数据类型,对象引用类型)、操作数栈、动态链接、方法出口等信息。注:局部变量表在所需内存空间,在编译时期已确定,运行期间不会改变局部变量表的大小
  • 本地方法栈:native方法使用的栈帧
  • 方法区:类信息,常量,静态变量,即时编译器编译后的代码等数据
    • 运行时常量池:属于方法区的一部分,用于存储编译时期生成的各种字面量和符号引用
  • Heap:堆内存(存放对象实例)


  • 直接内存:不属于虚拟机运行时数据区的一部分,且不是java虚拟机规范的内存区域。但被经常使用。JDK1.4中新加入的NIO,引入通道Channel和缓冲区Buffer的I/O方式,他可以通过Natative函数库直接分配堆外内存(通过DirectByteBuffer对象作为这块内存引用进行操作)

对象的创建

指针压缩

​ 在堆中,32位的对象引用(指针)32/8Bits占4个字节,而64位的对象引用64/8bits占8个字节。也就是说,64位的对象引用大小是32位的2倍。64位JVM在支持更大堆的同时,由于对象引用变大却带来了性能问题。为了能够保持32位的性能,oop必须保留32位。由于java中采用8字节对齐的,利用这个特性,开启指针压缩后,在压缩过程中,将数据右移3位,保存到32位地址,在解压再把32位左移3位放大8倍。所以oop能表示的范围为4(字节)*8(位)+3(擦除的后三位),即35位,所以我们要求使用UseCompressedOops条件是堆内存在4GB*8=32GB以内。

  • java中使用 +XX:+UseCompressedOops开启指针压缩,
  • 开启指针压缩占用4字节,不开启占用8字节。UseCompressedOops其原理就是利用java中8字节对齐。
  • 如果GC堆大小在4G以下,直接砍掉高32位,避免了编码解码过程;
  • 如果GC堆大小在4G以上32G以下,则启用UseCompressedOop;
  • 如果GC堆大小大于32G,压指失效,使用原来的64位
怎么计算对象大小

一个空对象未开启指针压缩为:8B(markword)+8B(kclass point)+0B(数组)+ 0B(对齐填充)=16B

开启指针压缩为:8B(markword)+4B(kclass point)+0B(数组)+ 4B(对齐填充)=16B

java内存模型

由于对象的生命周期不一样,出现了分代,98%的对象在minorGC的时候会被回收掉

结合图一可以看到,新生代和老年代是分配在堆内存中,而1.8以前的永久代是分配在方法区,1.8以后的元空间(meta space)是一个独立的内存。

补充:32位系统最大支持232即4GB的内存,64位系统支持2(64-16),并非2^64次方,有16位的保留位

注意 ,元空间相当于是动态扩容,只要内存够用

虚拟机栈

虚拟机栈主要由局部变量表、操作数栈、动态链接、方法出口几个部分组成,默认大小为1024。

字节码指令表

  • 局部变量表(Local Variable Table)
  1. 是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量
  2. 局部变量表的基本单位为变量槽(slot);局部变量表存放的是方法参数和局部变量;虚拟机是通过索引定位的方式使用局部变量表。
  3. 局部变量表中第0位索引的 Slot 默认是用于传递方法所属对象实例的引用(reference),即 “this” 关键字指向的对象,分配完方法参数后,便会依次分配方法内部定义的局部变量
  4. 局部变量表存放着编译期可知的基本数据类型(boolean,byte、char、short、int、float、long、double)、对象引用和returnAddress(指向一条字节码指令地址)。其中long和double占两个局部变量空间(Slot),其余数据类型只占一
  5. 局部变量表是在编译时期就确定了的
  • 操作数栈
  1. 即为操作栈,同局部变量表一样,
  • 动态链接
  1. 指向运行时常量池(方法区)中该栈帧所属性方法的引用,此引用可能是直接地址,也可能是句柄(在windows中指向的是句柄)
  • 方法返回地址
  1. 执行引擎遇到一个方法返回的字节码指令
  2. 防止执行过程中遇到了异常
导致虚拟机栈溢出的原因有哪些?

调用链太长
死循环
无限递归

栈大小:通过java -XX:+PrintFlagsFinal -version | grep ThreadStack可以看到,默认的栈大小为1024,即1M。

同时需要注意:-Xss65K以下设置会报错如下,(提示最小值设置为108K,但是实际测试最小值为65k)

"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" -Xss10k -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\software\develop\idea\IntelliJ IDEA 2018.3.5\lib\idea_rt.jar=6085:D:\software\develop\idea\IntelliJ IDEA 2018.3.5\bin" -Dfile.encoding=UTF-8 -classpath "D:\software\develop\idea\IntelliJ IDEA 2018.3.5\lib\idea_rt.jar;D:\software\develop\idea\IntelliJ IDEA 2018.3.5\plugins\junit\lib\junit-rt.jar;D:\software\develop\idea\IntelliJ IDEA 2018.3.5\plugins\junit\lib\junit5-rt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;E:\developProject\learndemo\learning-demo\jvm-learn\target\test-classes;E:\developProject\learndemo\learning-demo\jvm-learn\target\classes;E:\saveDatas\mavenRepository\junit\junit\4.11\junit-4.11.jar;E:\saveDatas\mavenRepository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 com.mk.learn.StackOverFlowTestTest,test

Error: Could not create the Java Virtual Machine.
The stack size specified is too small, Specify at least 108k
Error: A fatal exception has occurred. Program will exit.
posted @ 2020-06-21 09:44  嗡嗡作响  阅读(50)  评论(0)    收藏  举报