
在一秒钟内看到本质的人和花半辈子也看不清一件事本质的人,自然是不一样的命运。——《教父》
在日常使用Java编码的过程中,你是否会遇到很多的技术上的问题,无从下手,没有思路,除了一部分框架上的问题外,肯定也有很多涉及到JVM的问题,比如OOM问题、多线程锁、垃圾回收、系统运行缓慢等等问题。
面对JVM问题,通过谷歌能解决大部分问题,但是这样的问题解决方式,是基于搜索的,大海捞针似的解决问题方法,以前有人遇到过类似的,并且文章里有具体解决方法,那是比较幸运的。
那么怎样才能像高手一样通过原理,直达问题本质,找到解决方法。
Java虚拟机运行原理了解一下!

Java 虚拟机将运行时内存区域划分为五个部分,
分别为方法区、堆、程序计数器、Java 方法栈和本地方法栈。
Java 程序编译而成的 class 文件,需要先加载至方法区中,方能在 Java 虚拟机中运行。
这五部分是运行时数据区,就是在程序启动后,把我们要用的数据放到哪里。
那运行时都有哪些数据?这些数据都存放到对应的哪个区域。
那我们就把JVM运行时的所有数据都找出来,然后再分分类,把这些数据放到对应的区域。
那么就把运行时产生的数据列出来看一看:
1.程序计数器:程序运行行号--》线程私有
2.Java方法栈:一个方法一个栈帧--》局部变量表、操作数栈、动态链接、方法出口--》线程私有
局部变量表:
各种基本数据类型(boolean、byte、char、short、int、float、long、double、对象引用、returnAddress类型)
3.Java堆:Java对象--》线程共享
4.方法区:类信息、常量、静态变量、即时编译后的代码的数据--》线程共享
5.本地方法栈:Native方法服务--》线程私有
以上基本把虚拟机对应的数据都列了出来。知道了JVM中有哪些数据,JVM有哪些区域,全局了然于胸,就算搬砖也能知道自己的每块儿砖在哪里,从哪儿搬到哪儿了。
那我们就看看这每块儿砖,是什么砖,怎么放到这些区域的。
程序计数器:程序计数器内存较小,可以理解为我们程序执行到哪一行,就记录哪一行,作为指示器用。
这个是线程私有的,可以理解为每个线程下,记录这个线程执行到哪一行的指令的地址。
Java方法栈:每个线程在执行时,都会分配一个方法栈。那么要运行一个程序,就是各种方法调用。
每一个方法就是一个栈帧,栈帧里面存储上面方法栈列出的变量。我们一般配置一个。
一个方法栈在256K 左右,可以想象如果我们在一个方法里面做递归调用,如果递归次数比较多,那么有大量的局部变量产生,就会把方法栈给撑爆了,StackOverflowError 这个异常就会报出来了。如果方法栈不是固定的大小,智能了,是自动扩展,从256K变成1024K 拿不到足够的内存空间,就会抛出OutOfMemoryError了。以后遇到这个就不用查了,瞬间定位问题,边上同事心底默默竖起大拇指。
方法区:每个线程都能在里面游荡,线程共享的,类信息、常量、静态变量 这些数据信息就是码放到这儿了。
如果我们搞出来的静态变量和常量比较多,那就要看看方法去是不是给的空间够不够大了。
-XX:Permsize=64m -XX: MaxPermSize=64M 这个配置。如果这个区域报了OutOfMemoryError异常
第一反应就是方法区是不是小了,要不要搞大点儿。
Java堆:这个空间是JVM中的最大一块儿,JVM的垃圾回收业主要在这里搞事情。这个里面就是大量的对象,并且把堆划出区块,分区进行存放回收。当然如果这个区域很多长久存在的对象不能回收,就会把方法栈给撑爆了,StackOverflowError,就会发生new 不出新对象,当然OutOfMemoryError 就会报在堆上了。
本地方法栈:与方法栈其实差不多,就是作用地方不同,所以区分开了。本地方法栈主要记录Native方法服,与方法栈相同,本地方法栈区也会抛出StackOverflowError和OutOfMemoryError异常。
上面是对JVM虚拟机的根据空间的不同使用进行了划分的五个部分。
对JVM的深入理解,就是针对线程和这些区域的作用方式详细展开。

