运行结构图
类加载器
作用:加载Class文件 ~
双亲委派机制
1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
2、保证核心.class不能被篡改。通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载
也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。
这样保证了Class执行安全。
Native 本地方法栈
凡是带Native关键字的,说明Java的作用范围达不到,回去调用底层的C语言的库
会进入本地方法栈
调用本地的接口 JNI
JNI作用:扩展了Java的使用,融合了不同的编程语言为Java所用!最初:c;c++
Java诞生的时候C,c++横行,它在内存区域专门开辟了一块标记区域:Native Method Stack,登记native方法,在
最终执行的时候,加载本地方法库中的方法通过JNI
PC寄存器
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向像一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。
方法区
Method Area 方法区
方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,比如构造函数,接口代码也在此定义,简单来说,所有定义的方法信息都保存在该区域,此区域属于共享区间;
静态变量,常量,类信息(构造方法,接口定义),运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关
栈 :数据结构
程序 = 数据结构 + 算法
栈:先进后出,后进先出 (类似于桶装水)
队列 :先进先出
栈内存 :主管程序的运行,生命周期和线程同步;
线程结束,栈内存也就是释放了。对于栈来说,不存在垃圾回收问题
栈:8大基本类型 + 对象引用 +实例方法
堆
Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。
类加载器读取类文件后,一般会把类,方法,常量,变量~,保存我们所有引用类型真实对象。
堆内存还要分为三个区域:
- 新生区(伊甸园区)Young/New
- 养老区 old
- 永久区 perm
新生代(Young generation):绝大多数最新被创建的对象都会被分配到这里,由于大部分在创建后很快变得不可达,很多对象被创建在新生代,然后“消失”。对象从这个区域“消失”的过程我们称之为:Minor GC 。
老年代(Old generation):对象没有变得不可达,并且从新生代周期中存活了下来,会被拷贝到这里。其区域分配的空间要比新生代多。也正由于其相对大的空间,发生在老年代的GC次数要比新生代少得多。对象从老年代中消失的过程,称之为:Major GC 或者 Full GC。
持久代(Permanent generation)也称之为 方法区(Method area):用于保存类常量以及字符串常量。注意,这个区域不是用于存储那些从老年代存活下来的对象,这个区域也可能发生GC。发生在这个区域的GC事件也被算为 Major GC 。只不过在这个区域发生GC的条件非常严苛,必须符合以下三种条件才会被回收:
1、所有实例被回收
2、加载该类的ClassLoader 被回收
3、Class 对象无法通过任何途径访问(包括反射)
JVM的生命周期
1、*启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点。
2、*运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动。
3、*消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出。
当在电脑上运行一个程序时,就会运行一个java虚拟机,java虚拟机总是开始于main方法,main方法是程序的起点。
java的线程一般分为两种:守护线程和普通线程。守护线程是java虚拟机自己使用的线程,比如GC线程就是一个守护线程,当然你可以把自己的线程设置为守护线程,注意:main方法启动的初始线程不是守护线程。
只要java虚拟机中还有普通线程在执行,java虚拟机就不会停止,如果有足够的权限,你可以调用exit()方法终止线程。
IDEA导出内存,堆的【dump】文件
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
-Xms #初始化内存分配大小
-Xmx #初始化最大内存
jprofile 【栈堆内存分析工具】
** **下载地址
A-J12-pedoc#455172-msk2a0m2ucvtr#48b4b7 #注册码