java虚拟机在执行程序的过程中会将内存划分为不同的区域,具体如图1-1所示.
JVM分为五个区域:堆、虚拟机栈、本地方法栈、方法区(元空间)、程序计数器
PS: 1.五个区域中,虚拟机栈、本地方法栈、程序计数器为线程私有、方法区和堆为线程共享区; 2.JVM中不同区域的占用大小不同,堆最大,程序计数器最小,Java中最多的“对象”就是放在堆中
堆得主要作用就是存储对象,它占用最大的内存空间堆区,也同样成为了java垃圾收集器的重要对象。因此也被称为“GC堆”。堆是jvm所有线程共有的。
图1-1-1
由于垃圾收集器GC采用分代收集算法,所以堆内存中也分成了 2/3年轻代,1/3老年代 。如图1-1-1所示。
JVM 内置的通用垃圾回收原则,堆内存划分为 Eden、Survivor 和 Tenured/Old 空间bai。GC一共分三种:MinorGC,Major GC v和Full GC。Full GC是清理整个堆空间—包括年轻代和永久代。有时候系统会频繁的FullGC,这时候需要去服务器查一下原因。
新生成的对象首先放到年轻代Eden区,当Eden空间满了,触发Minor GC,存活下来的对象移动到Survivor0区,Survivor0区满后触发执行Minor GC,Survivor0区存活对象移动到Suvivor1区,这样保证了一段时间内总有一个survivor区为空。经过多次Minor GC仍然存活的对象移动到老年代。老年代存储长期存活的对象,占满时会触发Major GC=Full GC,GC期间会停止所有线程等待GC完成,所以对响应要求高的应用尽量减少发生Major GC,避免响应超时。 Minor GC : 清理年轻代 Major GC : 清理老年代 Full GC : 清理整个堆空间,包括年轻代和永久代 所有GC都会停止应用所有线程。
关于新生代到老年代的规则:
如图1-1-2所示:
1.minorgc回收整个年轻带,挪一次分代年龄+1,长期存活的对象分代年龄达到15到老年代。或者survior满了会触发minorGC会自动到达老年代。
2.一批对象如果大于surviovr区域百分之五十直接进入老年代
3.为了避免大对象分分配内存是需要复制大对象会直接进入老年代
图1-1-2
JVMGC内部采用可达性分析算法回收对象,具体规则如图1-1-3所示,可达性算法是将“GC Roots”作为起点,搜索引用的对象,搜索到的对象打上标记。未搜索的标记为非垃圾对象。
图1-1-3
虚拟机栈中存储的是方法,栈中的数据都是以栈帧的格式存在,我们简称栈帧,栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。java虚拟机栈是线程私有的,它的生命周期是和线程一样。每个线程在创建的时候都会创建一个虚拟机栈。但是而在栈帧中分为操作数栈,局部变量,动态链接,返回地址等。
ps:1.每一个栈帧遵循先进后出后进先出的出栈入栈规则。
2.操作数栈:从局部变量中或者对象实例中复制常量或者变量到操作数栈,在随着计算将栈中元素出栈到局部变量或者返给方法调用者。通俗来说,就是传递参数的。
3.动态链接,每一个栈帧都会有一个指向运行时常量池(运行时常量池是在JVm在运行加载类的时候,把class文件里的常量放到运行时常量里。一个类对应一个运行时常量池)的引用,来支持方法与方法之间的调用。字节码中的方法调用指令就以常量池中方法的符号引用为参数。
4.局部变量中的对象指针指向堆
首先,什么是本地方法呢?JVM中的本地方法是指java带有修饰符native的方法,但是方法体不是用java写的。这一类方法被称为java本地方法。这类方法的存在的意义是为了弥补java代码不方便实现的缺陷而提出的。
本地方法栈,作用与java虚拟机栈类似。 区别是:虚拟机栈为虚拟机执行java方法服务,而本地方法是为native方法服务。
本地方法栈是线程私有的。它的生命周期与线程相同,每个线程只有一个。
1.线程共享。在虚拟机启动时候创建,所有jvm线程共享。
2.上文所提到的运行时常量池就是方法区的一部分。
3.被装载的class文件的信息存储在方法区中的运行时常量池中,他使用类装载器定义相应的class文件
4.用于存在已被虚拟机加载的类信息,常量,变量,静态变量
程序员写的代码其实在在jvm虚拟机中被转成了一条条指令集执行的。如下图。
图5-1
程序计数器也叫PC寄存器,是一块内存空间,如果将class文件进行反编译后,就能看到一条条的指令集,如图5-1动图所示,PC代表的就是程序计数器的计数。
他可以看作是线程所执行的字节码的行号指示器,在虚拟机中,字节码解释器工作时,就是根据程序计数器的值来选取下一条需要执行的指令。分支、循环、异常处理、跳转都是需要这个程序计数器来完成。当虚拟机正在执行一个本地方法也就是native方法时,程序计数器存储的值是undefined。程序计数器是私有的。它的生命周期与线程相同,每个线程都有一个。
1.加载主方法的class文件进入方法区,方法区加载类的信息。
2.执行程序后,方法区的方法入栈,栈给方法分配栈帧。
3.遇到new对象的情况就在堆中开辟这个类的实例空间
arthas:查看cpu,jvm调优工具
JVMGC垃圾收集器:在底层执行的时候,会停掉所有线程(stop the world 简称STW),尽量的减少full gc.
面试:1.为什么要设计STW?
2.能否对jVM调优,让其几乎不发生Full Gc
一篇看懂JVM底层详解,利用class反编译文件了解文件执行流程
原文:https://www.cnblogs.com/hglh/p/14522572.html